何时调用构造函数以及如何不调用它们

Mas*_* Hu 1 c++ constructor

class A
{
    public:
    A(){std::cout << "hello\n";}
};

class B
{
    A object;
    public:
    B(A aObject){ object = aObject;}
};

int main() {

    A object;
    B bObject(object);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

当我运行这个程序时,似乎我构造了两次A类,因为在我的控制台上"hello"被打印两次.所以我的问题是我究竟是在为A调用我的构造函数以及如何使它停止所以我只构造一次A,同时仍然将A对象传递给B.

cdh*_*wie 6

发生这种情况是因为您的B类包含类型的成员A.作为结构的一部分B,该B::object构件被构造,这需要对一个呼叫A的构造.所以你实际上有两个A实例:objectbObject.object.

因为你没有把objectB::B()的初始化列表,B::object是缺省构造. object = aObject;然后分配给现有的A存储object.因此,不是复制构造B::object,而是默认构造它(它负责你看到的第二个"你好"),然后为它分配一个新值.

编译器将为您提供一个拷贝构造函数A(const A &),因此您可以B::object从参数中复制构造,如下所示:

B(A aObject) : object(aObject) { }
Run Code Online (Sandbox Code Playgroud)

此构造函数不调用默认构造函数,也不包含默认构造函数中包含的代码.因此,调用此构造函数不会导致输出"hello".

请注意,您仍然会构造一个新的A(事实上​​,您将这样做两次,因为它aObject是按值传递的),但由于您没有自己定义复制构造函数,因此它不会包含将字符串写入的代码std::cout.

这里发生的相关事件的实际顺序是:

  1. A object;调用A::A()构造函数. (第一个"你好"是从这里打印出来的.)
  2. B bObject(object);将调用B::B(A)构造函数,但由于A参数是由值接受的,object因此首先A使用编译器生成的A::A(const A &)复制构造函数将其复制到新的临时文件中.
  3. B::B(A)构造函数被调用来创建bObject,传递临时A在最后一步构建.
  4. B构造函数内部,B::object对象是默认构造的,A::A()因为它不在构造函数的初始化列表中. (第二个"你好"是从这里打印出来的.)
  5. 最后,B::B(A)运行构造函数的主体,它将临时A对象(存储在其中aObject)的值分配给在前一步骤中构造的A包含的B::object内容.通过使用编译器生成的A & A::operator=(A const &)运算符完成此赋值.