为什么 C++ 复制构造函数在调用其子复制构造函数时行为不同
Why does the C++ copy constructor behave differently when calling its child copy constructor?
我有以下玩具类A及其子类B:
#include <iostream>
using namespace std;
class A
{
protected:
int a;
public:
A():a(1){cout<<"A default constructor..."<<endl;}
A(int i):a(i){cout<<"A non-default constructor..."<<endl;}
A(const A &ao){cout<<"A copy constructor..."<<endl; a=ao.a;}
};
class B:public A
{
private:
int b;
public:
B(int i,int j):A(i),b(j){cout<<"B constructor..."<<endl;}
//B(const B &bo){cout<<"B copy constructor... "<<endl; b=bo.b;}
void print(){cout<<endl<<"class B, a: "<<a<<" b: "<<b<<endl<<endl;}
};
int main()
{
B b1(3,8);
b1.print();
B b2=b1;
b2.print();
}
我发现如果我不为 B 类提供复制构造函数,编译器将为我合成一个,而该编译器使用我为类 A 提供的复制构造函数。但是,如果我确实为类 B 提供了一个复制构造函数,其中我没有显式调用基类 A 的复制构造函数(请参阅代码),编译器将调用类 A 的默认构造函数?为什么?
标准行为。这主要是为了一致性:任何未显式调用特定基类构造函数的用户定义构造函数都将调用默认构造函数。为什么复制构造函数会有所不同?
为派生类编写构造函数(任何构造函数)时,您可以(并且通常必须)在该构造函数的初始值设定项列表中显式初始化基类子对象。如果无法执行此操作,则编译器将隐式调用这些基类子对象的默认构造函数(假设它们可用)。此规则绝对适用于所有用户定义的构造函数。
这正是您案例中发生的事情。您忘记在 B::B(const B&)
的构造函数中初始化基A
,因此默认构造函数用于该基。在这种情况下,B::B(const B&)
是一个复制构造函数这一事实没有任何区别。同样,对于所有类型的用户定义构造函数,它始终以这种方式工作。
现在,如果不提供用户定义的复制构造函数,则编译器将尝试隐式提供 on。隐式定义的复制构造函数将尝试调用所有基类的复制构造函数。语言规范只是说编译器提供的复制构造函数以这种方式运行,这就是您的"为什么"问题的答案。
规则的顺序适用于此处。只能通过提供自己的构造函数来取代该规则。
您没有注意到的是,成员数据的处理方式与基类数据相同:如果编译器提供复制构造函数,则通过复制构造初始化,但如果编写存根复制构造函数,则默认构造初始化。
通过实现复制构造函数,您告诉编译器您将决定如何初始化成员和基类。 如果您没有其他说明,这些将使用默认方法进行初始化。
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- 当从函数参数中的临时值调用复制构造函数时
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 复制构造函数、赋值运算符C++
- std::ofstream 作为类成员删除复制构造函数?
- 复制构造函数C++无法正确复制指针
- 关于复制构造函数的一个棘手问题
- 为什么调用复制构造函数而不是移动构造函数?
- 填充上编译器生成的复制构造函数之间的不一致
- C++ 对象指针数组的复制构造函数
- C++ 基本 CTOR 说明 - 为什么不调用赋值/复制构造函数
- 防止在复制构造函数中隐式调用基构造函数
- 为用户定义的类正确调用复制构造函数/赋值运算符
- 具有已删除移动和复制构造函数的类的就地构造
- 复制构造函数隐式转换问题
- 复制构造函数中的递归调用