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

时间:2014-11-06 22:25:42

标签: 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;
}

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

3 个答案:

答案 0 :(得分:6)

这是因为您的B类包含A类型的成员。作为构造B的一部分,构造了B::object成员,这需要调用A构造函数。因此,您实际上有两个A个实例:objectbObject.object

由于您没有将object放入B::B()的初始值设定项列表中,因此B::object是默认构造的。 object = aObject;然后分配给A 中存储的现有object。因此,不是复制构造B::object,而是默认构造它(它负责你看到的第二个“你好”),然后你为它分配一个新值。

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

B(A aObject) : object(aObject) { }

此构造函数不调用默认构造函数,也不包含默认构造函数中包含的代码。因此,调用此构造函数 not 会导致输出“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 {1}},它是在前一步骤中构建的。通过使用编译器生成的A & A::operator=(A const &)运算符完成此分配。

答案 1 :(得分:0)

B构造函数在正文执行之前构造B的所有成员。如果您未明确指定如何构造成员,则将使用默认构造函数。要避免调用A的默认构造函数,可以指定复制构造函数:

B(A aObject) : object(aObject) {}

这将避免两次调用默认构造函数(一次在main()中,一次在B()构造函数中)。

(还有其他方法可以做到这一点,例如使用移动构造函数。)

答案 2 :(得分:0)

字符串A object;是您首先创建A类对象的地方