为什么虚拟基础classes必须由最派生的class构造?
Why must virtual base classes be constructed by the most derived class?
以下代码无法编译:
class A {
public:
A(int) {}
};
class B: virtual public A {
public:
B(): A(0) {}
};
// most derived class
class C: public B {
public:
C() {} // wrong!!!
};
如果我在C
的构造函数初始化列表中调用A
的构造函数,即:
// most derived class
class C: public B {
public:
C(): A(0) {} // OK!!!
};
确实有效。
显然,原因是因为 虚拟基础 类 必须始终由 最派生的 类[=27= 构造].
我不明白这个限制背后的原因。
因为它避免了这个:
class A {
public:
A(int) {}
};
class B0: virtual public A {
public:
B0(): A(0) {}
};
class B1: virtual public A {
public:
B1(): A(1) {}
};
class C: public B0, public B1 {
public:
C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};
因为在 class 层次结构中有一个虚拟继承的基础 class,基础 class would/may 被多个 class 共享(在菱形中例如继承,其中相同的基础 class 被多个 class 继承)。这意味着,虚拟继承的基础 class 只有一个副本。它本质上意味着,必须首先构造基础 class 。它最终意味着派生 class 必须实例化给定的基础 class。
例如:
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.
我发现此规则容易出错且麻烦(但是,多重继承的哪一部分不是?)。
但是逻辑上强加的构造顺序必须不同于正常(非虚拟)继承的情况。考虑 Ajay 的示例,减去虚拟:
class A;
class B1 : A;
class B2 : A;
class C: B1,B2
在这种情况下,对于每个 C 构造了两个 A,一个作为 B1 的一部分,另一个作为 B2 的一部分。 B classes 的代码对此负责,并且可以做到。事件顺序是:
Start C ctor
Start B1 ctor
A ctor (in B's ctor code)
End B1 ctor
Start B2 ctor
A ctor (in B's ctor code)
End B2 ctor
End C ctor
现在考虑
中的虚拟继承
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2
一个事件顺序是
Start C ctor
A ctor // not B's code!
Start B1 ctor
// NO A ctor
End B1 ctor
Start B2 ctor
// NO A ctor
End B2 ctor
End C ctor
重要的逻辑区别在于,类型 A 的虚拟继承基 class 子对象是最派生 class 的 部分,并且在控制它(这里C
)。
B 的构造函数对 A
一无所知,也无法访问。因此它们不能构造 A
的子对象,包括基础 classes.
以下代码无法编译:
class A {
public:
A(int) {}
};
class B: virtual public A {
public:
B(): A(0) {}
};
// most derived class
class C: public B {
public:
C() {} // wrong!!!
};
如果我在C
的构造函数初始化列表中调用A
的构造函数,即:
// most derived class
class C: public B {
public:
C(): A(0) {} // OK!!!
};
确实有效。
显然,原因是因为 虚拟基础 类 必须始终由 最派生的 类[=27= 构造].
我不明白这个限制背后的原因。
因为它避免了这个:
class A {
public:
A(int) {}
};
class B0: virtual public A {
public:
B0(): A(0) {}
};
class B1: virtual public A {
public:
B1(): A(1) {}
};
class C: public B0, public B1 {
public:
C() {} // How is A constructed? A(0) from B0 or A(1) from B1?
};
因为在 class 层次结构中有一个虚拟继承的基础 class,基础 class would/may 被多个 class 共享(在菱形中例如继承,其中相同的基础 class 被多个 class 继承)。这意味着,虚拟继承的基础 class 只有一个副本。它本质上意味着,必须首先构造基础 class 。它最终意味着派生 class 必须实例化给定的基础 class。
例如:
class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2 // A is shared, and would have one copy only.
我发现此规则容易出错且麻烦(但是,多重继承的哪一部分不是?)。
但是逻辑上强加的构造顺序必须不同于正常(非虚拟)继承的情况。考虑 Ajay 的示例,减去虚拟:
class A;
class B1 : A;
class B2 : A;
class C: B1,B2
在这种情况下,对于每个 C 构造了两个 A,一个作为 B1 的一部分,另一个作为 B2 的一部分。 B classes 的代码对此负责,并且可以做到。事件顺序是:
Start C ctor
Start B1 ctor
A ctor (in B's ctor code)
End B1 ctor
Start B2 ctor
A ctor (in B's ctor code)
End B2 ctor
End C ctor
现在考虑
中的虚拟继承class A;
class B1 : virtual A;
class B2 : virtual A;
class C: B1,B2
一个事件顺序是
Start C ctor
A ctor // not B's code!
Start B1 ctor
// NO A ctor
End B1 ctor
Start B2 ctor
// NO A ctor
End B2 ctor
End C ctor
重要的逻辑区别在于,类型 A 的虚拟继承基 class 子对象是最派生 class 的 部分,并且在控制它(这里C
)。
B 的构造函数对 A
一无所知,也无法访问。因此它们不能构造 A
的子对象,包括基础 classes.