我有以下c ++代码(如果这很重要,VS2013(:
#include <iostream>
using namespace std;
struct A{
A() { cout << "A()" << endl; }
A(int i) { cout << "A(" << i << ")" << endl; }
};
struct B : /*virtual*/ public A{
B(int i) : A(i){ cout << "B(" << i << ")" << endl; }
};
struct C : /*virtual*/ public A{
C(int i) : A(i){ cout << "C(" << i << ")" << endl; }
};
struct D : /*virtual*/ public B, /*virtual*/ public C{
D() : B(2), C(3){ cout << "D()" << endl; }
};
void main() {
D d;
system("pause");
}
该代码实现了菱形继承,总共有 4 个继承: B:A, C:A, D:B, D:C
由于这些继承都没有设置为virtual
,我得到以下输出:
A(2( B(2( A(3( C(3( D((
这是有道理的。D(
( 首先调用 B(int x(,它首先调用 A(int x(,然后调用 C(int x(,它首先调用 A(int x(,最后 D(( 本身运行。 但就虚拟继承而言,我有 4 个继承,这意味着我总共有 16 个虚拟\非虚拟继承的组合。
弄乱不同的选项会产生一些非常意想不到的结果,我对虚拟继承的了解越多,我似乎就越困惑。
以下是一些示例:
- 当仅将 B:A 设置为
virtual
时,我得到:
A(( B(2( A(3( C(3( D((
这是有道理的 - B 虚拟继承 A,因此,除非另有特别说明,否则 B(int x( 调用 A 的默认构造函数。
- 当仅将 C:A 设置为
virtual
时,我得到:
A(( A(2( B(2( C(3( D((
为什么 A 的构造函数都先于 B 和 C ?这种行为对我来说毫无意义。
- 当仅将 D:C 设置为
virtual
时,我得到:
A(3( C(3( A(2( B(2( D((
为什么 C 的构造函数会先于 B 的构造函数?
我可以继续说下去。 其中一些组合会导致非常意想不到的结果(至少对我来说(。
我知道虚拟继承的基础知识,并在简单的示例中理解它们,并且我看到了很多关于它的问题。但其中一些行为仍然让我感到困惑。
这些多个虚拟继承是否遵循任何特定的规则集?
编辑: 我被重定向到这个问题: 混合基类的虚拟和非虚拟继承 虽然这很有帮助,但我仍然对在任何特定情况下调用 A 的哪个构造函数感到困惑。 我仍然需要一些帮助。
这里有两个大键:
虚拟基类由派生最多的类构造函数直接初始化,而不是由其他基类间接初始化。
虚拟基类在任何非虚拟基类之前初始化。
因此,让我们看一下您的示例。
当仅将 B:A 设置为虚拟时,我得到:
A(( B(2( A(3( C(3( D((
这是有道理的 - B 虚拟继承 A,因此,除非另有特别说明,否则 B(int x( 调用 A 的默认构造函数。
B
根本不调用A
的构造函数。D
直接调用A
A
的虚拟实例。 但是由于D
的构造函数没有指定如何初始化A
,所以你会得到A
的默认构造函数。
B(int i) : A(i)
中的A
被忽略不是因为A
是一个虚拟基,而是因为B
不是派生最多的类,因此无法构造其A
。
当仅将 C:A 设置为虚拟时,我得到:
A(( A(2( B(2( C(3( D((
为什么 A 的构造函数都先于 B 和 C ?这种行为对我来说毫无意义。
这里C::A
是唯一的虚拟基类,所以它首先被初始化。 同样,由于D
的构造函数没有为A
指定初始值设定项,因此该虚拟子对象使用默认构造函数。
然后,非虚拟基类按顺序排列。B
在C
之前,但B
首先需要初始化其非虚拟A
(使用2
(。
当仅将 D:C 设置为虚拟时,我得到:
A(3( C(3( A(2( B(2( D((
为什么 C 的构造函数会先于 B 的构造函数?
唯一的虚拟基类是C
,所以它在B
之前构造。 但是这次C
的构造函数必须首先初始化其非虚拟基子对象C::A
。 然后是B
,它必须首先初始化其非虚拟子对象B::A
。
最后,还有"正常"模式,它使A
继承都是虚拟的,导致只有一个A
子对象,这是虚拟继承的全部点。 将B
或C
虚拟化是没有意义的,除非您希望D
以更复杂的方式重用为基类。
#include <iostream>
using namespace std;
struct A{
A() { cout << "A()" << endl; }
A(int i) { cout << "A(" << i << ")" << endl; }
};
struct B : virtual public A{
B(int i) : A(i){ cout << "B(" << i << ")" << endl; }
};
struct C : virtual public A{
C(int i) : A(i){ cout << "C(" << i << ")" << endl; }
};
struct D : public B, public C{
D() : A(1), B(2), C(3){ cout << "D()" << endl; }
};
void main() {
D d;
system("pause");
}
输出:
A(1( B(2( C(3( D((
注意我在D
中添加了一个初始值设定项A(1)
,以表明虚拟子对象不一定需要使用默认构造函数。 您可以在至少一个A
继承是虚拟的任何示例中执行此操作。