类似梯形的C ++虚拟继承

时间:2018-03-27 04:21:23

标签: c++ multiple-inheritance virtual-inheritance

如果我有类继承关系,如下所示

               a
              /  \
             b    c
              \   |
               |  d
                \/ \
                e   f
                 \ /
                  g

以下是正确的定义吗?

    class A {};
    class B: public virtual A {};
    class C: public virtual A {};
    class D: public C {};
    class E: public B, public virtual D  {};
    class F: public virtual D {};
    class G: public E, public F {};

我让A和D几乎都是遗传的,因为我认为每个联合课都需要是虚拟的。

此外,我不确定C ++如何定义上述情况的构造函数顺序。链接 https://isocpp.org/wiki/faq/multiple-inheritance#mi-vi-ctor-order

  

要执行的第一个构造函数是虚拟基础   层次结构中的任何类。它们按照它们的顺序执行   出现在基础图的深度优先从左到右的遍历中   类,从左到右指的是基数的出现顺序   班级名称。

     

完成所有虚拟基类构造函数之后   构造顺序通常是从基类到派生类。该   如果您想象第一个,那么细节最容易理解   编译器在派生类的ctor中做的事情就是创建一个   隐藏调用其非虚拟基类的ctors(提示:那是   许多编译器实际执行的方式)。所以,如果D类继承   从B1和B2相乘,B1的构造函数先执行,然后执行   B2的构造函数,然后是D的构造函数。这个规则是   递归地应用;例如,如果B1继承自B1a和B1b,和   B2继承自B2a和B2b,最后的顺序是B1a,B1b,B1,   B2a,B2b,B2,D。

     

请注意,顺序B1和B2(或B1a然后B1b)由下式确定   基类出现在声明中的顺序   class,而不是初始化程序在派生中出现的顺序   class的初始化列表。

如果是,那顺序是什么?

  A, D, B, C, D, F, G

我不认为D是在C之前构造的。什么是正确的构造函数顺序?

2 个答案:

答案 0 :(得分:9)

构造类A的对象时,首先初始化虚拟基类。这导致调用DD的构造函数。 C的构造函数将构造它的基础G对象。然后将调用E的非基类的构造函数,即FEB的构造函数将调用A C D B E F G 的构造函数。这给出了最终的顺序:

{{1}}

答案 1 :(得分:6)

我添加了调用printf的构造函数来观察发生了什么(Godbolt上的代码可用于好奇)。我得到的订单,包括clang(版本6.0.0)和gcc(版本6.4.0和7.3.0),是:

A
C
D
B
E
F
G

这符合我的期望。必须首先构造AD,但是如果没有C,则无法构造D(想象一下D的构造函数调用{C的更复杂的示例{1}}。一旦满足所有virtual继承,就会按照我们期望的顺序调用构造函数。