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。
答案 0 :(得分:6)
这是因为您的B
类包含A
类型的成员。作为构造B
的一部分,构造了B::object
成员,这需要调用A
构造函数。因此,您实际上有两个A
个实例:object
和bObject.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
的代码。
此处发生的相关事件的实际顺序是:
A object;
调用A::A()
构造函数。 (第一个“你好”从这里打印出来。) B bObject(object);
将调用B::B(A)
构造函数,但由于A
参数已被值接受,因此object
首先会被复制到新的临时A
中使用编译器生成的A::A(const A &)
拷贝构造函数。B::B(A)
构造函数来创建bObject
,传入最后一步构建的临时A
。B
构造函数内部,B::object
对象是使用A::A()
默认构造的,因为它不在构造函数的初始化列表中。 (第二个“你好”从这里打印出来。) 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类对象的地方