class A: public B, public C { };
在这种情况下,执行顺序是:
B(); // base(first)
C(); // base(second)
A(); // derived
class A: public B, virtual public C { };
但是在这种情况下,当我在继承时用类c写virtual时,
的顺序// execution becomes:
C(); // virtual base
B(); // ordinary base
A(); // derived
我在某个地方读到,调用构造函数的顺序取决于继承多个类时声明的顺序,但是在用类写virtual时执行顺序如何改变。我不明白为什么会得到这样的结果。
根据c++标准,总是先执行虚基类构造函数。从N3242工作草案,272页第10行,我们得知:
- 虚拟基类构造函数优先,按照从左到右深度优先遍历继承图的顺序。 直接基类是下一个,按照声明顺序。
所以你看到的行为正是c++标准所要求的。这是有道理的,因为虚拟基类可能在继承中出现多次,当然每个基类只能构造一次。因此,必须先构造第一轮虚基类,然后再构造通常的非虚基类。
本页也有很好的解释
如果你有一个虚拟类作为父类,你不能希望初始化总是按照声明的顺序进行。事实上,第一个父类(比如非虚拟)本身可能依赖于虚拟类。因此,在这种情况下,必须首先构造虚类。
我想这就是为什么c++规范说虚拟父类的初始化函数总是首先执行的原因。如@Dan Roche所示,初始化顺序是可预测的。
的例子:
class B: public A {...}
class C: public B, virtual A {...}
在这个例子中,在C的初始化中,不可能在A之前初始化B,因为B的初始化需要先初始化A。
另一个例子这个例子展示了你不应该依赖基类的初始化顺序:
#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的初始化顺序颠倒了。这意味着如果你想让别人扩展你的类,你就不能依赖于虚拟基类初始化的顺序。