编译如何选择要调用的构造函数?

时间:2019-07-08 13:53:50

标签: c++ class constructor copy-constructor default-copy-constructor

这是我的代码。

删除第11行时,输出为

A(0)
B(0)
A(1)

关于最后一行“ A(1)”,为什么要调用类A的第二个构造函数?

#include <iostream>

using namespace std;

class A {
public:
   A() { cout << "A(0)" << endl; }
   A(const A& a) { cout << "A(1)" << endl; }
};

class B {
public:
    B() : a() { cout << "B(0)" << endl; }
    // B(const B& b) { cout << "B(1)" << endl; }
private:
    A a;
};

int main() {
   B object1;
   B object2 = object1;
   return 0;
}
A(0)
B(0)
A(1)

5 个答案:

答案 0 :(得分:7)

何时

B(const B& b) { cout << "B(1)" << endl; }

被注释掉/删除,编译器会为您生成一个副本构造函数。提供的复制构造函数将复制该类的所有成员,因此在这种情况下,它将删除一个看起来像

的复制构造函数
B(const B& copy) : a(copy.a) {}

这就是为什么看到a的副本构造函数的原因。

当您不评论/删除

B(const B& b) { cout << "B(1)" << endl; }

您不要复制a,因为您没有告诉它这样做。编译器所做的是通过将构造函数转换为

为其创建默认初始化
B(const B& b) : a() { cout << "B(1)" << endl; }

因此将调用默认构造函数,而不是复制构造函数。

答案 1 :(得分:1)

编译器正在为您生成一个copy constructor,它将复制成员a。为了复制成员a,它依次调用其复制构造函数,并打印A(1)

答案 2 :(得分:0)

因为object2是用B的隐式副本构造函数初始化的。一个隐式副本构造函数隐式复制该类的所有数据成员,因此调用了A的副本构造函数,它显示“ A(1) “。

答案 3 :(得分:0)

B类的编译器(带有注释的副本构造函数)隐式定义了默认的副本构造函数,该默认副本构造函数调用类成员的副本构造函数。

根据C ++ 20标准(11.3.4.2复制/移动构造函数)

  

14非工会类的隐式定义的复制/移动构造函数   X对它的基础和成员执行成员复制/移动...

B类的隐式定义的默认副本构造函数看起来像

B( const B &b ) : a( b.a )
{
}

这是一个演示程序

#include <iostream>

using namespace std;

class A {
public:
   A() { cout << "A(0)" << endl; }
   A(const A& a) { cout << "A(1)" << endl; }
};

class B {
public:
    B() : a() { cout << "B(0)" << endl; }
    // An analogy of the implicitly declared copy constructor
    B(const B& b) : a( b.a ){}
private:
    A a;
};

int main() {
   B object1;
   B object2 = object1;
   return 0;
}

程序输出将与删除与编译器隐式生成的副本构造函数相对应的类B的副本构造函数相同。

A(0)
B(0)
A(1)

答案 4 :(得分:0)

您遇到的问题与思考注释第11行有关,意味着您已删除该构造函数。

在C ++中,即使最终没有使用它们,也会自动生成一些构造函数,即使您自己没有声明它们。具有与B中注释掉的构造器相同的签名的复制构造器就是其中之一。

在您的情况下,您最终要首先调用B的默认构造函数,该构造函数也首先使用默认构造函数构造它的成员A。这应该给出您所看到的输出,由于成员初始化顺序,在A的副本构造函数的主体之前到达B的主体。

然后,使用赋值运算符创建一个类型为B的新对象,该运算符隐式调用现在生成的B的副本构造函数。这意味着A的副本构造函数也被调用,这是B的副本构造函数如何使用的规则自动生成。取消注释A的复制构造函数,然后使用打印输出调用它。