为什么C ++拷贝构造函数在调用其子拷贝构造函数时表现不同?

时间:2013-09-08 19:18:47

标签: c++

我有以下玩具类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的默认CONSTRUCTOR吗?那是为什么?

4 个答案:

答案 0 :(得分:9)

这是标准行为。它主要是为了保持一致性:任何用户定义的构造函数都没有显式调用特定的基类构造函数,它将调用默认的构造函数。为什么复制构造函数会有所不同?

答案 1 :(得分:1)

当您为派生类编写构造函数(任何构造函数)时,可以(通常必须)在该构造函数的初始化列表中显式初始化基类子对象。如果您没有这样做,那么编译器将隐式调用那些基类子对象的默认构造函数,假设它们可用。此规则适用于绝对所有用户定义的构造函数。

这正是你案件中发生的事情。您忘记在A的构造函数中初始化基础B::B(const B&),因此默认构造函数用于该基础。在这种情况下,B::B(const B&)复制构造函数的事实没有任何区别。对于各种用户定义的构造函数,它同样适用于这种方式。

现在,如果您不提供用户定义的复制构造函数,那么编译器将尝试隐式提供。隐式定义的复制构造函数将尝试为所有基类调用复制构造函数。语言规范只是说编译器提供的复制构造函数就是这样,这就是你“问题”问题的答案。

答案 2 :(得分:0)

初始化规则的顺序适用于此处。您只能通过提供自己的构造函数来取代该规则。

答案 3 :(得分:0)

您没有注意到的是 成员数据的处理方式与基类数据 的处理方式相同:它由副本初始化-construction如果编译器提供了复制构造函数,但是如果你编写了一个存根复制构造函数,则由default-construction初始化。

通过实现复制构造函数,您告诉编译器您将决定如何初始化成员和基类 。如果没有您的其他说明,将使用默认方法初始化这些说明。