关于以下代码如何运行,我有几个问题
using namespace std;
class A
{
int i;
public:
A() { i = 7; cout << 1 << f() << i; }
A(int i) :i(i) { cout << 1 << f() << i; }
char f() { return 'A'; }
};
class B : public virtual A
{
int i;
public:
B(int i) : A(i), i(++i) { cout << 2 << i; }
virtual char f() { return 'B'; }
};
class C : public virtual A {
public:
C(int i) : A(i) { cout << 3 << i; }
virtual char f() { return 'C'; }
};
class D :public A {
public:
D(int i) { cout << 4 << i; }
virtual char f() { return 'D'; }
};
class E : public B, public C, public D {
public:
E() : B(2), C(3), D(4) { cout << 5; }
virtual char f() { return 'E'; }
};
int main()
{
E e;
return 0;
}
因此输出应为'1A723331A7445'。
答案 0 :(得分:1)
是的,所以让我先说你已经创建了一个真正混乱的类型层次结构。如果您试图了解初始化顺序,那么这个例子可能会让您感到困惑。
无论如何,为了使事情更清楚,I modified your code并在每个c&#39; tor打印语句的末尾添加斜杠/
字符。因此,我们可以更容易地辨别线的哪一部分属于每个c。tor。这给出了以下输出:
1A7 / 23/33 / 1A7 / 44/5'/ P>
在我进入初始化顺序之前,您应该知道您指定的所有虚拟函数都是通过动态调度获得的。 c c体中的虚函数将静态绑定。因此,对于我们的意图和目的,您并没有在代码中调用虚拟函数。
现在,引用C ++标准,这就是确定初始化顺序的方式([class.base.init]/13):
在非委托构造函数中,初始化继续进行 以下顺序:
首先,仅对于派生程度最高的类的构造函数,虚拟基类按照它们出现在的顺序进行初始化 深度优先从左到右遍历有向无环图 基类,其中“从左到右”是出现的顺序 派生类 base-specifier-list 中的基类。
然后,直接基类按声明顺序初始化,因为它们出现在 base-specifier-list 中(无论顺序如何) mem-initializers )。
然后,非静态数据成员按照它们在类定义中声明的顺序进行初始化(同样无论顺序如何 MEM-初始化)。
最后,执行构造函数体的复合语句。
所以让我们分开你的初始化:
1)虚拟A
子对象是默认构造的,因为你没有在E()
的成员初始化列表中指定它,它为对象执行A()
共享B
和C
,并打印1A7/
。
2)现在调用了B
的c&t,以B(int i)
执行i = 2
。它将B::i
设置为3
,并且c&#39;身体打印23/
。
3)通过C
调用C(int i)
来构建i = 3
。这会打印33/
。
4)现在是时候构建D
了。因此,您使用D(int i)
致电i = 4
。由于D
非虚拟地从A
继承,因此它将具有需要构建现在的独特A
子对象。
您再次没有在成员初始值设定项列表中为其指定参数,因此A
是默认构造的。这会打印1A7/
。
现在D(int i)
的正文已运行,并打印44/
。
5)最后,调用E()
的正文,并打印5
。