混合基类

时间:2016-02-10 11:44:35

标签: 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;
}

此代码打印:

Biology CTOR
Biology CTOR
Human CTOR
Animal CTOR
Centaur CTOR

为什么?

由于我们创建了一个Centaur对象,我们从构建CentaurHuman和最后Animal开始构建Centaur(我们从少开始派生到最派生的。)

让我们从Human开始: Human继承自Biology,因此我们首先调用Biology的构造函数。 现在构造了Human的基类,我们最终可以构造Human本身。 但相反, Biology会再次构建!

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

请注意,完全故意让AnimalBiology继承,并且同时故意将Human非虚拟地继承自Biology }。

我们正在以错误的方式解决 Dreaded Diamond 人类和动物应该实际上继承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个实例。

这是什么逻辑?

请尝试解释一下你的方式,我已经检查过很多关于此事的网站。但似乎没有一个能满足我的要求。

3 个答案:

答案 0 :(得分:38)

从输出中可以清楚地看到两个func centralManager(central: CBCentralManager, didConnectPeripheral peripheral: CBPeripheral) { print("inside didConnectPeripheral ...") print("Data : \(peripheral.identifier) : \(peripheral.description)") peripheral.delegate = self let customService:CBUUID = CBUUID(string: Constants.UUID.CustomServcices) peripheral.discoverServices([customService]) } 对象被实例化。这是因为您已经只有一个继承Biology。两个基类实例是可怕钻石问题模棱两可的原因,解决方案是(我们知道) virtual Biology继承。

回顾层次结构:

virtual

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

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

第一个输出 - Biology Biology | | # one and only one inheritance virtual Human Animal \ / Centaur 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 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

  

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

     

- 首先,仅适用于最多的构造函数   派生类(1.8),虚拟基类按顺序初始化   它们出现在深度优先的从左到右的遍历中   基类的非循环图,其中“从左到右”是基数的顺序   派生类中基类的外观   基符列表

     

- 然后,在中初始化直接基类   声明顺序显示在 base-specifier-list 中   (无论 mem-initializers 的顺序如何)。

     

...

答案 1 :(得分:2)

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

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

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

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

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

答案 2 :(得分:1)

  1. Biology虚拟继承的所有基类在它们之间共享一个Biology基础实例。
  2. Biology继承非虚拟的所有基类都有Biology的每个实例。
  3. 每个类别中都有一个基础,因此Biology引入Human的一个实例(原则上与其他人共享)和Animal引入的一个实例(从未与任何其他基类共享。)