混合基类的虚拟和非虚拟继承 [英] Mixing virtual and non-virtual inheritance of a base class

查看:101
本文介绍了混合基类的虚拟和非虚拟继承的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是代码:

  struct Biology 
{
Biology(){cout< < 生物CTOR endl; }
};

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

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

struct半人马:人类,动物
{
Centaur(){cout< Centaur CTOR< endl; }
};

int main()
{
Centaur c;

return 0;
}

此代码打印:

 生物学CTOR 
生物学CTOR
人类CTOR
动物CTOR
Centaur CTOR

为什么?



由于我们创建了 Centaur 对象,我们从构建人类动物开始构建 Centaur c $ c>,最后 Centaur (我们从较少派生到最多派生)。



人类:
人类继承自生物学 ,因此我们首先调用 Biology 的构造函数。
现在人类的基类被构造,我们可以最终构造人类本身。
但是, 生物会再次构建!



为什么?



请注意,这完全是故意留下 Animal 生物学,同时,也有意留下非虚拟地继承自 code>。



我们正在以不正确的方式解决恐惧钻石:人类和动物应该实际上继承生物让这项工作。



我只是好奇。



  struct Biology 
{
Biology(){cout< 生物CTOR endl; }
};

struct人类:虚拟生物学
{
Human(){cout< 人CTOR endl; }
};

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

struct半人马:人类,动物
{
Centaur(){cout< Centaur CTOR< endl; }
};

int main()
{
Centaur c;

return 0;
}

这里我们有 Human Biology ,而 Animal 实际上继承于 Biology b
$ b

但这次输出是不同的:

 生物CTOR 
人类CTOR
生物学CTOR
动物CTOR
Centaur CTOR

Centaur 继承开始人类 code> Animal



如果顺序是相反的,我们将获得与前面相同的结果示例 - 两个生物实例在一行中构建。



这是什么逻辑?



请尝试解释你的方式,我已经检查了吨网站谈论这个。

解决方案

从输出中可以清楚地看出 two 对象已实例化。这是因为您已使只有一个继承 virtual 。两个基类实例是可怕的钻石问题的模糊的原因,解决方案是使两个继承生物 virtual



层次结构:

 生物学生物学
| | #一并且只有一个继承虚拟
人动物
\ /
Centaur


$ b b

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




  • 基类是在派生类之前构造的。

  • 基本类按照它们出现在 base-specifier-list 中的顺序构建。

  • 在最常见的派生类之前的非虚拟类之前构建 - 请参阅此。 li>


第一个输出 - 动物 virtual



<$ p> 生物学CTOR#virtual base class继承自Animal
生物CTOR#人类的非虚拟基类
人类CTOR#人类本身
动物CTOR#已经构建的动物虚拟基类
Centaur CTOR

第二个输出 - code>生物学:

 生物CTOR#虚拟基类继承自人类
人类CTOR#已经构建的人类虚拟基类
生物CTOR#非虚拟基类动物
动物CTOR#动物本身
Centaur CTOR






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


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



- 首先,只有最多的构造函数
派生类(1.8),虚拟基类按照
的顺序初始化,它们出现在基本类的定向的
非循环图的深度优先从左到右的遍历中,其中left-to -right是派生类
base-specifier-list 中基类的
出现的顺序。



- 然后,直接基类在
声明顺序中初始化,因为它们出现在 base-specifier-list
中(不管

...



This is the code:

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

This code prints:

Biology CTOR
Biology CTOR
Human CTOR
Animal CTOR
Centaur CTOR

Why?

Since we create a Centaur object, we start from building the Centaur by constructing Human, Animal and finally Centaur (we start from the less derived to the most derived).

Let's start from Human: Human inherits from Biology, so we call Biology's constructor first. Now that Human's base class is constructed, we can finally construct the Human itself. But instead, Biology gets constructed again!

Why? What's happening behind the scenes?

Please note that it was completely intentional leaving Animal inheriting virtually from Biology and, at the same time, it was also intentional leaving Human non-virtually inheriting from Biology.

We are solving the Dreaded Diamond in an incorrect way: both Human and Animal should virtually inherit Biology to make this work.

I'm just curious.

Also, see this code:

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

Here we have Human inheriting virtually from Biology, while Animal is set to inherit in the "classic way".

But this time, the output is different:

Biology CTOR
Human CTOR
Biology CTOR
Animal CTOR
Centaur CTOR

This because Centaur inherits at first from Human and then from Animal.

Had the order been the inverse, we'd have achieved the same result as before, in the first example - two Biology instances being constructed in a row.

What's the logic of this?

Please try to explain your way, I've already checked tons of websites speaking about this. But none seems to satisfy my request.

解决方案

It's clear from the output that two Biology objects are instantiated. That is because you've made only one inheritance virtual. Two base class instances is the cause of ambiguity in dreaded diamond problem and the solution is to make (as we know) both inheritances of Biology virtual.

Recap of the hierarchy:

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

Ok, let's read the output again with these rules in mind:

  • Base classes are constructed before derived classes.
  • Base classes are constructed in order in which they appear in the base-specifier-list.
  • Virtual base classes are constructed before non-virtual ones by the most derived class - see this.

1st output - Animal virtually inherits from 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

2nd output - Human virtually inherits from 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


More informational standard paragraph ([class.base.init]/10):

In a non-delegating constructor, initialization proceeds in the following order:

— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where "left-to-right" is the order of appearance of the base classes in the derived class base-specifier-list.

— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

...

这篇关于混合基类的虚拟和非虚拟继承的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆