大家好,
我想知道在使用虚拟基类的多重继承时编译器如何处理不同的初始化值。考虑臭名昭着的“恐惧钻石”继承计划:
Base
/ \
/ \
D1 D2
\ /
\ /
Join
为了避免Base
中有Join
的两个副本,我使用D1
和D2
的虚拟继承(请参阅例如here)。现在,假设Base
不是抽象的,但有一个成员字段,在其构造函数中初始化:
class Base {
public:
Base(int x_) {x = x_;};
virtual ~Base(){};
public:
int x;
};
class D1 : public virtual Base {
public:
D1() : Base(1) {};
virtual ~D1(){};
};
class D2 : public virtual Base {
public:
D2() : Base(2) {};
virtual ~D2(){};
};
class Join : public D1, public D2 {
public:
Join(){};
~Join(){};
};
int main()
{
Join j;
cout << j.x << endl;
return 0;
}
输出是1,2还是依赖于编译器?
答案 0 :(得分:5)
它没有编译。虚拟基础由最派生的类Join
初始化。 Join
未明确初始化Base
,但Base
没有可访问的默认构造函数。
[它也不会编译,因为类的定义需要用;
终止,但我认为这是一个错字。 main
也应返回int
,我认为j.x
是j->x
的拼写错误。]
答案 1 :(得分:2)
当你有虚拟继承时,它必须初始化虚拟基类。
因此,Join的构造函数必须构造Base:
class Join : public D1, public D2
{
public:
Join() : Base(3){} // or whatever value
~Join(){}
};
规则的例外是类通常只初始化它们的直接基类。
(除了main
应该返回int
,你需要做j->x
而不是j.x
,因为j是一个指针,以及你必须delete
{1}}正如您所说的那样new
)
答案 2 :(得分:1)
由于Base没有隐式构造函数,并且C1
和C2
都是虚拟基础,你必须像这样更改它(并且在其余的类声明后添加分号为Charles Bailey指出)
class Join : public D1, public D2 {
public:
Join() : Base(3) {};
~Join(){};
};
int main()
{
Join j;
cout << j.x << endl;
}
然后它会将3
打印到标准输出