创建涉及虚拟继承的类的过程

ZER*_*ERO 6 c++ inheritance diamond-problem

在许多描述虚拟基类(通常用于解决钻石问题)的教程中,它们通常都有类似于此结构设计的代码:

class Animal
{
public:
    Animal()
    {
        cout << "Creating Animal\n";
    }
};

///////////////////////////

class FourLegs : virtual public Animal
{
public:
    FourLegs()
    {
        cout << "Creating FourLegs\n";
    }
};

///////////////////////////

class Mammal : virtual public Animal
{
public:
    Mammal()
    {
        cout << "Creating Mammal\n";
    }
};

///////////////////////////

class Fox : public FourLegs, public Mammal
{
public:
    Fox()
    {
        cout << "Creating Fox\n";
    }
};
Run Code Online (Sandbox Code Playgroud)

当我创建Fox的实例时,我得到了预期的输出,只创建了一个Animal:

Creating Animal
Creating FourLegs
Creating Mammal
Creating Fox
Run Code Online (Sandbox Code Playgroud)

如您所见,我有两个二级类继承虚拟.现在,如果只有一个二级类被虚拟继承,而另一个只是公开继承,那么就会出现有趣的输出.例如,如果FourLegs是继承的公共和Mammal继承虚拟公共,这是输出:

Creating Animal
Creating Animal
Creating FourLegs
Creating Mammal
Creating Fox
Run Code Online (Sandbox Code Playgroud)

这很奇怪,并提出了一个问题:在继承树中某处创建涉及虚拟继承的类的完整过程是什么?

另一方面,如果我的FourLegs如果继承了虚拟公共,而Mammal是继承公共的,那么输出就像正常一样(好像什么都没有继承虚拟公共):

Creating Animal
Creating FourLegs
Creating Animal
Creating Mammal
Creating Fox
Run Code Online (Sandbox Code Playgroud)

K-b*_*llo 3

直接来自标准12.6.2/10 [class.base.init]

\n\n
\n

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

\n\n
    \n
  • 首先,并且仅对于最派生类 (1.8) 的构造函数,虚拟基类按照它们在基类有向无环图的深度优先从左到右遍历中出现的顺序进行初始化,其中 \xe2\ x80\x9cleft-to-right\xe2\x80\x9d 是派生类base-specifier-list中基类的出现顺序。

  • \n
  • 然后,直接基类按照它们出现在基本说明符列表中的声明顺序进行初始化(无论mem-initializers的顺序如何)。

  • \n
  • 然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样无论mem-initializers的顺序如何)。

  • \n
  • 最后,执行构造函数体的复合语句。

  • \n
\n\n

[注意:声明顺序必须确保基类和成员子对象以与初始化相反的顺序销毁。\xe2\x80\x94结束注]

\n
\n\n

第一条解释了如何对涉及虚拟继承的类进行初始化。

\n