混合基类的虚拟和非虚拟继承

ged*_*ial 27 c++ inheritance constructor multiple-inheritance virtual-inheritance

这是代码:

struct Biology
{    
    Biology() { cout << "Biology CTOR" << endl; }
};

struct Human : Biology
{    
    Human() { cout << "Human CTOR" << endl; }
};

struct Animal : virtual Biology
{
    Animal() { cout << "Animal CTOR" << endl; }
};

struct Centaur : Human, Animal
{
    Centaur() { cout << "Centaur CTOR" << endl; }
};

int main()
{   
   Centaur c;

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

此代码打印:

Biology CTOR
Biology CTOR
Human CTOR
Animal CTOR
Centaur CTOR
Run Code Online (Sandbox Code Playgroud)

为什么?

由于我们创建了一个Centaur对象,我们从构建Centaur构建开始Human,Animal最后Centaur(我们从较少派生到最派生).

让我们从Human: Human继承Biology,所以我们先调用Biology构造函数.现在Human构建了基类,我们终于可以构建Human自己了.但相反,Biology再次构建!

为什么?幕后发生了什么?

请注意,这是完全故意留下Animal的几乎继承Biology,并在同一时间,也有人故意留下Human非虚拟继承Biology.

我们正在以一种错误的方式解决可怕的钻石:人类和动物都应该实际上继承生物学以使其发挥作用.

我只是好奇.

另外,请参阅此代码:

struct Biology
{    
    Biology() { cout << "Biology CTOR" << endl; }
};

struct Human : virtual Biology
{
    Human() { cout << "Human CTOR" << endl; }
};

struct Animal : Biology
{    
    Animal() { cout << "Animal CTOR" << endl; }
};

struct Centaur : Human, Animal
{
    Centaur() { cout << "Centaur CTOR" << endl; }
};

int main()
{   
   Centaur c;

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

这里我们Human实际上是从继承Biology,而Animal设置为继承"经典方式".

但这一次,输出是不同的:

Biology CTOR
Human CTOR
Biology CTOR
Animal CTOR
Centaur CTOR
Run Code Online (Sandbox Code Playgroud)

这是因为Centaur继承了最初HumanAnimal.

如果顺序是反向的,那么在第一个例子中我们已经获得了与之前相同的结果 - Biology连续构造了两个实例.

这是什么逻辑?

请尝试解释一下你的方式,我已经检查了很多关于这个的网站.但似乎没有人满足我的要求.

Log*_*uff 39

从输出中可以清楚地看到两个Biology对象被实例化.那是因为你只做了一次继承virtual.两个基类实例是可怕的钻石问题的模糊性的原因,解决方案是(如我们所知)两个遗传Biology virtual.

回顾层次结构:

Biology  Biology
   |       |     # one and only one inheritance virtual
Human     Animal
    \     /
    Centaur
Run Code Online (Sandbox Code Playgroud)

好的,让我们再次阅读输出,并考虑以下规则:

  • 基类在派生类之前构造.
  • 基类按照它们出现在base-specifier-list中的顺序构造.
  • 虚拟基类由非派生类在非派生类之前构建 - 请参阅此内容.

第一个输出 - Animal virtual继承自Biology:

Biology CTOR     # virtual base class inherited from Animal
Biology CTOR     # non-virtual base class of Human
Human CTOR       # Human itself
Animal CTOR      # Animal's virtual base class already constructed
Centaur CTOR
Run Code Online (Sandbox Code Playgroud)

第二个输出 - Human virtual继承自Biology:

Biology CTOR     # virtual base class inherited from Human
Human CTOR       # Human's virtual base class already constructed
Biology CTOR     # non-virtual base class of Animal
Animal CTOR      # Animal itself
Centaur CTOR
Run Code Online (Sandbox Code Playgroud)

更具信息性的标准段落([class.base.init]/10):

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

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

- 然后,直接基类按声明顺序初始化,因为它们出现在base-specifier-list中 (无论mem-initializers的顺序如何).

...

  • 这个答案是金。谢谢 ;) (2认同)