【发布时间】:2018-12-17 11:47:35
【问题描述】:
在我的代码中,我有一个基本的菱形图案:
CommonBase
/ \
/ \
DerivedA DerivedB
\ /
\ /
Joined
它是这样实现的,通用基类有一个默认构造函数和一个带参数的构造函数:
struct CommonBase {
CommonBase() : CommonBase(0) {}
CommonBase(int val) : value(val) {}
const int value;
};
struct DerivedA : public virtual CommonBase {
void printValue() {
std::cout << "The value is " << value << "\n";
}
};
struct DerivedB : public virtual CommonBase {
void printValueTimes2() {
std::cout << "value * 2 is " << value * 2 << "\n";
}
};
struct Joined : public DerivedA,
public DerivedB {
Joined(int val) : CommonBase(val) {
std::cout << "Constructor value is " << val << "\n";
std::cout << "Actual value is " << value << "\n";
}
};
Joined 类使用带参数的构造函数初始化虚基,一切都按预期工作。
但是,当我从 Joined 类派生一个类时,会发生一些奇怪的事情 - 除非我在派生类构造函数中显式初始化 CommonBase,否则会调用 CommonBase 的 默认构造函数也是。
使用以下代码演示:
struct JoinedDerivedA : public Joined {
JoinedDerivedA() : Joined(99) {
printValue();
}
};
struct JoinedDerivedB : public Joined {
JoinedDerivedB() : Joined(99), CommonBase(99) {
printValue();
}
};
int main() {
std::cout << "======= Joined =======\n";
Joined j(99);
j.printValue();
std::cout << "\n=== JoinedDerivedA ===\n";
JoinedDerivedA a;
std::cout << "\n=== JoinedDerivedB ===\n";
JoinedDerivedB b;
return 0;
}
这段代码的输出是
======= Joined =======
Constructor value is 99
Actual value is 99
The value is 99
=== JoinedDerivedA ===
Constructor value is 99
Actual value is 0 // <-- unexpected behaviour
The value is 0
=== JoinedDerivedB ===
Constructor value is 99
Actual value is 99
The value is 99
为什么会这样?是否可以不必再次显式初始化派生类中的公共基类?
这是ideone上的代码,你可以自己运行:https://ideone.com/Ie94kb
【问题讨论】:
-
当您拥有虚拟继承时,每个人都只有一个共享的基类子对象,该子对象虚拟地派生自该基类。并且该子对象存在于最派生的类中。它还应该住在哪里?真的没有任何其他地方可以始终以明确的方式放置它。你可能想看看stackoverflow.com/questions/6461784/…
-
@MichaelKenzel 我知道共享基类只有一个实例,但是我希望它存在于
Joined类中,因为该类显式调用基类构造函数,类似于非虚拟继承。 -
如果有另一个基类在其构造函数中也调用了虚基类的构造函数呢?
-
这是一个非常好的问题,如果有人能解释为什么它是在 C++ 中以这种方式实现的,而不是仅仅声明最派生类必须初始化虚拟基地。
标签: c++ inheritance diamond-problem