2014-09-24 25 views
0

我遇到过这个让我困惑的问题。复杂的构建顺序 - 涉及虚拟继承

这个代码是:

struct B1 { B1(){std::cout << "B1\n";} }; 
    struct V1 : public B1 { V1(){std::cout << "V1\n";} }; 
    struct D1 : virtual public V1 {D1(){std::cout << "D1\n";} }; 

    struct B2 {B2(){std::cout << "B2\n";} }; 
    struct B3 {B3(){std::cout << "B3\n";} }; 
    struct V2 : public B1, public B2 {V2(){std::cout << "V2\n";} }; 
    struct D2 : public B3, virtual public V2 {D2(){std::cout << "D2\n";} }; 
    struct X : public D1, public D2 { }; 

问:什么是建筑X的顺序?

这里是我与简化IT

enter image description here

首先,我想回答这个事实,认为没有虚继承这个问题的目的是构建一个图。关键字virtualpublic代替我会得到

B1,V1,D1, [B3,B1,B2,V2,D2] , X 

但是我不知道,当虚拟继承走来我会如何处理这个问题。它提到的代码。我读到它的解决方法完全一样,但virtual bases优先。这里有哪些虚拟基地?有关如何解决这个问题的任何建议?

+0

该图不正确,两个'B1'实例是分开的。 – 2014-09-24 05:58:14

+0

我不确定如果'V1'是'虚拟公共B1'但是'V2'是(非虚拟)'public B1',会发生什么情况! – 2014-09-24 05:59:46

+0

@MattMcNabb虚拟的虚拟构建器实际上由'X'的构造器构造,非虚拟构造器通过V2的构造器非虚拟构造;你最终得到两个'B1'子对象。 – 2014-09-24 06:55:34

回答

2

这里的规则(§12.6.2[class.base.init]/P11):

在非委托构造,在 初始化前进顺序如下:

  • 首先,仅对于派生类(1.8)的构造函数,虚拟基类按其在 基类的有向无环图的深度优先从左到右的遍历中出现的顺序进行初始化,其中“从左到右“是的出现顺序派生类中的基类基指定符列表
  • 然后,直接基类在声明的顺序,因为它们出现在碱说明符列表(不管 MEM-初始化的顺序)进行初始化。
  • 然后,非静态数据成员将按照它们在类定义中声明的顺序进行初始化(不管 成分初始化程序的顺序如何)。
  • 最后,执行构造函数体的复合语句

所以,如果V1和V2是虚拟的基础,然后建设进入V1 - > V2 - > D1 - > D2 - > X的复合语句。 V1的构造函数将首先构造一个B1,然后执行它的主体。 V2的构造函数将构造一个B1和一个B2,然后执行它的主体。 D2的构造函数将在执行它的主体之前构造一个B3。 (因为D1和D2都不是最派生类,所以它们的构造函数不会构造虚拟基类V1或V2)。因此,整体打印顺序为B1→V1→B1→B2→V2→D1→ B3→D2→X.

如果V1和V2不是虚拟碱基,那么X的构造就是D1→D2→X. D1具有单个直接基底V1,V1具有单个直接基底B1 ,所以你得到第一部分B1 - > V1 - > D1。同样的,你为第二部分构造B3→B1→B2→V2→D2,所以总体顺序为B1→V1→D1→B3→B1→B2→V2→D2-> > X.

+0

由于D2不是派生类最多的,所以'D2'没有调用'V2'的构造函数吗? – 0x499602D2 2014-09-24 03:59:33

+0

@ 0x499602D2在虚拟基础情况下?是。 – 2014-09-24 04:04:46

+0

第一个要点不明确,是否说图中出现的所有虚拟基类都是先初始化的;或者只是'X'直接继承的那些? – 2014-09-24 05:52:28