繁体   English   中英

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

[英]Mixing virtual and non-virtual inheritance of a base class

这是代码:

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

此代码打印:

Biology CTOR
Biology CTOR
Human CTOR
Animal CTOR
Centaur CTOR

为什么?

因为我们创建了一个Centaur对象,所以我们从构建Centaur开始,构建HumanAnimal ,最后构建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;
}

在这里,我们将Human虚拟地从Biology继承,而Animal设置为以“经典方式”继承。

但这一次,输出不同:

Biology CTOR
Human CTOR
Biology CTOR
Animal CTOR
Centaur CTOR

这是因为Centaur首先Human继承然后Animal继承。

如果顺序是相反的,我们将获得与之前相同的结果,在第一个示例中 - 连续构造两个Biology实例。

这是什么逻辑?

请尝试解释你的方式,我已经检查了大量关于这个的网站。 但似乎没有一个能满足我的要求。

从输出中可以清楚地看出,两个Biology对象已被实例化 那是因为你只做了一个继承virtual 两个基类实例是可怕的菱形问题中歧义的原因,解决方案是(如我们所知)使Biology两个继承成为virtual

层次结构回顾:

Biology  Biology
   |       |     # one and only one inheritance virtual
 Human   Animal
    \     /
    Centaur

好的,让我们记住这些规则再次阅读输出:

  • 基类在派生类之前构造。
  • 基类是按照它们在base-specifier-list 中出现的顺序构造的。
  • 虚拟基类由最派生的类在非虚拟基类之前构造- 请参阅this

1输出- Animal virtual从LY继承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

第二个输出 - 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

更多信息标准段落[class.base.init]/10

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

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

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

...

非虚拟继承是一种排他关系,就像成员资格一样。 一个类可以是给定完整对象中另一个类的非虚拟基类。

这意味着一个类可以覆盖非虚基类的虚函数而不会引起冲突或问题。

构造函数也可以可靠地初始化非虚拟基类。

只有虚拟基类可以是一个完整对象的许多间接基类的直接基类。 由于可以共享虚拟基类,因此覆盖程序可能会发生冲突。

构造函数可以尝试初始化 ctor-init-list 中的虚拟基子对象,但如果进一步派生该类,则 ctor-init-list 的那部分将被忽略。

  1. Biology虚拟继承的所有基类在它们之间共享一个Biology基实例。
  2. 所有的基类,从继承非虚拟Biology有一个实例每个Biology

您在每个类别中都有一个基础,因此您有一个由Human引入的Biology实例(原则上与其他人共享)和一个由Animal引入的实例(从未与任何其他基类共享)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM