多重继承的情况下的执行顺序

时间:2014-07-13 12:45:19

标签: c++ multiple-inheritance

class A: public B, public C { };

在这种情况下,执行顺序为:

B(); // base(first)  
C(); // base(second)  
A(); // derived

class A: public B, virtual public C { }; 

但是在这种情况下,当我继承时使用类c写虚拟,

的顺序
// execution becomes:  
C(); // virtual base  
B(); // ordinary base  
A(); // derived

我已经读过某个地方,调用构造函数的顺序依赖于继承多个类的声明顺序,但是如何在用类编写虚拟时更改执行顺序。我无法理解为什么我得到这样的结果

2 个答案:

答案 0 :(得分:5)

始终根据C ++标准首先执行虚拟基类构造函数。从工作草案N3242,第272页第10行,我们了解到:

  • 虚拟基类构造函数首先按照继承图的从左到右深度优先遍历的顺序排在第一位。
  • 接下来是直接基类,按声明顺序。

因此,您看到的行为正是C ++标准所要求的。这是有道理的,因为虚拟基类可能在继承中出现多次,当然它们每个只能构造一次。因此必须有一个初始的虚拟基类构造,然后是通常的非虚基类构造。

this page还有一个很好的解释。

答案 1 :(得分:1)

如果您将虚拟类作为父类,则无法希望初始化始终按声明顺序进行。实际上,第一个(比如说非虚拟的)父类可能本身依赖于虚拟类。因此,在这种情况下,必须首先构造虚拟类。

我认为这就是为什么C ++规范说虚拟父类的初始化器总是先执行的原因。正如@Dan Roche所示,有一个可预测的初始化顺序。

示例:

class B: public A {...}
class C: public B, virtual A {...}

在C的初始化示例中,由于B的初始化需要首先初始化A,因此无法在A之前初始化B.

另一个例子 这个例子表明你不应该依赖基类初始化顺序:

#include <iostream>
using namespace std;

struct A {
  A() {cout<<"A()"<<endl;}
};

struct B {
  B() {cout<<"B()"<<endl;}
};

struct C: virtual A, virtual B {
  C() {cout<<"C()"<<endl;}
};

struct D: virtual B, virtual A, C {
  D() {cout<<"D()"<<endl;}
};  

int  main() {
  cout<<"construct C"<<endl;
  new C;
  cout<<"construct D"<<endl;
  new D;
}

输出:

construct C
A()
B()
C()
construct D
B()
A()
C()
D()

如示例所示,当C被构造为D的基类时,A和B的初始化顺序相反。这意味着如果您希望某人可以扩展您的类,则不能依赖虚拟基类的初始化顺序。