【问题标题】:C++ virtual base classes: parent's copy constructor doesn't get calledC++ 虚拟基类:不调用父级的复制构造函数
【发布时间】:2015-06-09 23:11:58
【问题描述】:

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

#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;
}

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

Child(other) 不应该打电话给Parent(other) 吗?而且Parent(other)不应该反过来打电话给Abstract(other)吗?

【问题讨论】:

  • 你怎么知道Parent(other)没有被调用?请在每个构造函数主体中添加几个 printfs 或 cout &lt;&lt;s 以查看调用的内容。请用结果更新问题。
  • 请让所有构造函数初始化同一个类中定义的所有数据成员,例如Abstract(): mA(-1) {};
  • 虚拟基类只能由最派生类初始化。其他构造函数调用被忽略并替换为默认构造函数调用。
  • @0x499602D2:应该作为答案发布。

标签: c++ class copy-constructor


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

    为了正确调用Abstract的拷贝构造函数,你需要在Child拷贝构造函数的初始化列表中指定。

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

    DEMO

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

    §12.6.2,(13.1):

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2012-05-19
      • 2021-04-15
      • 2013-06-27
      • 2011-03-30
      • 2011-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多