C ++虚拟基类:不会调用父级的复制构造函数

时间:2015-06-09 23:11:59

标签: c++ class copy-constructor

我在下面的代码中看到了三个类。请注意我是如何编写复制构造函数的。

#include <iostream>

class Abstract
{
public:
    Abstract(){};
    Abstract( const Abstract& other ): mA(other.mA){};
    virtual ~Abstract(){};

    void setA(double inA){mA = inA;};
    double getA(){return mA;};

    virtual void isAbstract() = 0;
protected:
    double mA;
};

class Parent : public virtual Abstract
{
public:
    Parent(){};
    Parent( const Parent& other ): Abstract(other){};
    virtual ~Parent(){};

};


class Child : public virtual Parent
{
public:
    Child(){};
    Child( const Child& other ): Parent(other){};
    virtual ~Child(){};

    void isAbstract(){};
};


int main()
{
    Child child1;
    child1.setA(5);

    Child childCopy(child1);
    std::cout << childCopy.getA() << std::endl;
    return 0;
}

现在为什么在构建Abstract()时调用Abstract( const Abstract& other )而不是复制构造函数childCopy

不应Child(other)致电Parent(other)?并且Parent(other)不应该拨打Abstract(other)

2 个答案:

答案 0 :(得分:5)

虚拟基类只能由派生程度最高的类初始化。从非最派生类调用虚拟基础的构造函数将被忽略,并替换为默认构造函数调用。这是为了确保虚拟基础子对象只初始化一次:

正确的代码应该将构造函数调用放在派生类最多的类' ctor-initializer 中:

Child(Child const& other)
    : Abstract(other) // indirect virtual bases are
                      // initialized first
    , Parent(other) // followed by direct bases
{ }

答案 1 :(得分:1)

为了正确调用Abstract的复制构造函数,您需要在Child的复制构造函数的初始化列表中指定它。

Child( const Child& other ): Abstract(other), Parent(other) {};

DEMO

以下是该标准的相关引用,该引用声明虚拟基类的构造函数仅在最派生类中调用。如果缺少,则调用默认构造函数(如果它存在)。

  

§12.6.2,(13.1):

     

在非委托构造函数中,初始化按以下顺序进行:

     
      
  • 首先,仅适用于派生程度最高的类(1.8)的构造函数,   虚拟基类按照它们出现在的顺序进行初始化   深度优先从左到右遍历有向无环图   基类,其中“从左到右”是出现的顺序   派生类base-specifier-list中的基类。
  •   

特别是,这就是为什么你注意到Abstract的默认构造函数被调用的原因。

但是,为了避免这种缺陷,您可以删除所有用户定义的复制构造函数,并依赖于隐式定义的复制构造函数(这总是一个好主意)。 DEMO 2