C++ 虚拟继承和构造函数
C++ Virtual inheritance and constructors
我有以下 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
将这些继承中的 none 设置为 virtual
,我得到以下输出:
A(2) B(2) A(3) C(3) D()
有道理。 D()先调用B(int x),B(int x)先调用A(int x),再调用C(int x),C(int x)先调用A(int x),最后D()自己运行。
但是就虚拟继承而言,我有4个继承,也就是说我总共有16种virtual\not-virtual继承组合。
摆弄不同的选项会产生一些非常意想不到的结果,而且我对虚拟继承的了解越多,我就越感到困惑。
这里有一些例子:
- 仅将 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 的哪些构造函数感到困惑。
我还需要一些帮助。
这里有两个大键:
虚拟基 classes 由最派生的 class 构造函数直接初始化,而不是由其他基 classes 间接初始化。
虚拟基 classes 在任何非虚拟基 classes 之前初始化。
让我们看看你的例子。
When setting only B:A to virtual I get:
A() B(2) A(3) C(3) D()
That makes some sense - B inherits A virtually, and therefore, unless specifically stated otherwise, B(int x) calls A's default constructor.
B
根本不调用 A
的构造函数。 D
直接为 A
的虚拟实例调用 A
。但是由于 D
的构造函数没有指定如何初始化 A
,所以你得到 A
的默认构造函数。
B(int i) : A(i)
中的 A
被忽略不是因为 A
是虚拟基础,而是因为 B
不是最衍生的 class 等等无法构建其 A
.
When setting only C:A to virtual I get:
A() A(2) B(2) C(3) D()
Why do A's constructors both precede B's and C's? That behavior makes no sense to me.
这里C::A
是唯一的虚拟基class,所以先初始化。同样,由于 D
的构造函数没有为 A
指定初始化程序,该虚拟子对象使用默认构造函数。
然后非虚拟基地classes按顺序进行。 B
出现在 C
之前,但 B
首先需要初始化其非虚拟 A
(与 2
)。
When setting only D:C to virtual I get:
A(3) C(3) A(2) B(2) D()
Why would C's constructor precede B's?
唯一的虚拟基地 class 是 C
,因此它是在 B
之前建造的。但是这次C
的构造函数必须先初始化它的非虚基子对象C::A
。然后是B
,它必须首先初始化它的非虚拟子对象B::A
。
最后是“正常”模式,它使两个 A
继承都是虚拟的,结果只有一个 A
子对象,这是虚拟继承的全部要点。将 B
或 C
虚拟化是没有意义的,除非您希望 D
以更复杂的方式被重用为基础 class。
#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
继承是虚拟的任何示例中完成此操作。
我有以下 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
将这些继承中的 none 设置为 virtual
,我得到以下输出:
A(2) B(2) A(3) C(3) D()
有道理。 D()先调用B(int x),B(int x)先调用A(int x),再调用C(int x),C(int x)先调用A(int x),最后D()自己运行。
但是就虚拟继承而言,我有4个继承,也就是说我总共有16种virtual\not-virtual继承组合。
摆弄不同的选项会产生一些非常意想不到的结果,而且我对虚拟继承的了解越多,我就越感到困惑。
这里有一些例子:
- 仅将 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 的构造函数?
我可以继续下去。 其中一些组合会导致非常意外的结果(至少对我而言)。
我了解虚拟继承的基础知识并通过简单的示例理解它们,并且我已经看到很多关于它的问题。但是其中一些行为仍然让我感到困惑。
这些多重虚拟继承是否有任何特定的规则集?
编辑:
我被重定向到这个问题:
这里有两个大键:
虚拟基 classes 由最派生的 class 构造函数直接初始化,而不是由其他基 classes 间接初始化。
虚拟基 classes 在任何非虚拟基 classes 之前初始化。
让我们看看你的例子。
When setting only B:A to virtual I get:
A() B(2) A(3) C(3) D()
That makes some sense - B inherits A virtually, and therefore, unless specifically stated otherwise, B(int x) calls A's default constructor.
B
根本不调用 A
的构造函数。 D
直接为 A
的虚拟实例调用 A
。但是由于 D
的构造函数没有指定如何初始化 A
,所以你得到 A
的默认构造函数。
B(int i) : A(i)
中的 A
被忽略不是因为 A
是虚拟基础,而是因为 B
不是最衍生的 class 等等无法构建其 A
.
When setting only C:A to virtual I get:
A() A(2) B(2) C(3) D()
Why do A's constructors both precede B's and C's? That behavior makes no sense to me.
这里C::A
是唯一的虚拟基class,所以先初始化。同样,由于 D
的构造函数没有为 A
指定初始化程序,该虚拟子对象使用默认构造函数。
然后非虚拟基地classes按顺序进行。 B
出现在 C
之前,但 B
首先需要初始化其非虚拟 A
(与 2
)。
When setting only D:C to virtual I get:
A(3) C(3) A(2) B(2) D()
Why would C's constructor precede B's?
唯一的虚拟基地 class 是 C
,因此它是在 B
之前建造的。但是这次C
的构造函数必须先初始化它的非虚基子对象C::A
。然后是B
,它必须首先初始化它的非虚拟子对象B::A
。
最后是“正常”模式,它使两个 A
继承都是虚拟的,结果只有一个 A
子对象,这是虚拟继承的全部要点。将 B
或 C
虚拟化是没有意义的,除非您希望 D
以更复杂的方式被重用为基础 class。
#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
继承是虚拟的任何示例中完成此操作。