假设我有一个基类 A 和类 B 派生自它。B 类的 C 类等等...... Z 类的 Y。
当我实例化类 Z 时,谁将负责初始化类 A 的数据成员?
从类继承时,基类的构造函数在派生类之前调用。您可以使用初始化列表控制传递给它的内容:
struct A
{
A();
A(int);
}
struct B
{
B(){} // A() is called implicitly.
B(int x) : A(x) {} // A(int) is called explicitly.
}
沿着链派生的任何类都可以负责初始化数据成员,具体取决于它们的可访问性。
一种常见的方法是让类 A 的构造函数要求数据成员的值。B 类会将这些变量添加到它的构造函数中,依此类推。
它可以是 A 到 Z 中的任何一个,这完全取决于您的情况。如果 A 类在其构造函数中使用参数 ab 和 c ,则 B 类必须提供这些参数,如果它在其构造函数中又期望 abc 被传递,那么它将由 C 类提供这些等等。子类可能会选择提供一个尚未在构造函数中传递的值,因此后续子类将不再需要提供此值。
AFAIK,A 的构造函数将负责 A 的数据成员的初始化,因为类是自上而下构造的,或 Base-before-Derived。这就是为什么您不能在构造函数中使用纯虚成员函数的原因,因为尚未创建定义它的派生类。
每个类的每个构造函数都构造所有直接的非虚拟基类。这递归地解释了您的设置中发生的情况。
相比之下,虚拟基类是由最派生类的构造函数构造的。
这是一个明确提到基本构造函数的典型示例:
struct A { A(int, int) { /* ... */ ; };
struct B : A { B(char, bool) : A(2, 3) { /* ... */ };
struct C : B { C() : B('x', false) { /* ... */ };
C c; // calls A::A(2, 3), then B::B('x', false), then C::C()