我有一个关于类继承的问题。
我认为以下代码将解释我的问题:
struct A {
int x;
};
struct B: A {
};
struct C: A {
};
struct D: B, C {
D() : x(1) {}
};
int main() {
D d;
}
代码无法编译。
问题是:如何创建 struct D 的实例?谢谢!
最佳答案
您正在尝试做的事情有两个问题。
D
没有名为 x
的成员,它有两个名为 x
的成员.具体来说,D::B::x
和 D::C::x
, 由于多重继承和称为 diamond problem 的某个问题.作为B
和 C
来自 A
,它们每个都包含 A
的全部内容在他们的定义中,因此每个都包含自己的A::x
.所以,当 D
源自 B
和 C
, 它包含一个完整的 B
和整个 C
在其自身中,包括他们的A
s。它看起来像这样(使用 MSVC 生成,使用编译器开关 -d1reportSingleClassLayout
):class D size(8):
+---
| +--- (base class B)
| | +--- (base class A)
0 | | | x
| | +---
| +---
| +--- (base class C)
| | +--- (base class A)
4 | | | x
| | +---
| +---
+---
您应该改为修改
B
和 C
从 A 虚拟继承,如:struct B: virtual A {
};
struct C: virtual A {
};
这将导致
B
和 C
到,而不是包含它们的基数 A
,无论他们走到哪里,让它跟随他们:class B size(8):
+---
0 | {vbptr}
+---
+--- (virtual base A)
4 | x
+---
class C size(8):
+---
0 | {vbptr}
+---
+--- (virtual base A)
4 | x
+---
这反过来又允许
D
拍一张A
,坚持A
到它的背上,告诉他们俩这是他们的A
,解决菱形问题并允许他们共享同一个实例。class D size(12):
+---
| +--- (base class B)
0 | | {vbptr}
| +---
| +--- (base class C)
4 | | {vbptr}
| +---
+---
+--- (virtual base A)
8 | x
+---
因此,
D
应该将参数传递给 A
的构造函数,所以他们可以初始化字段。struct A {
int x;
// If A() has no parameter specified, it sets x to 4.
A(int x_ = 4) : x(x_) {}
};
struct B: virtual A {
// If B constructs A, it tells it to set x to 3 unless otherwise specified.
B(int x_ = 3) : A(x_) {}
};
struct C: virtual A {
// If C constructs A, it tells it to set x to 2 unless otherwise specified.
C(int x_ = 2) : A(x_) {}
};
struct D: B, C {
// This will actually set D.x to 4; since D constructs A, neither B() nor C() will
// call A(). D() will call A() without specifying a parameter.
// D() : B(1), C(1) {}
// This, however, gets the job done. Tells A to set x to 1.
D() : A(1) {}
};
然后,当你构造
d
...int main() {
D d;
}
其成员(member)
d.x
现在将设置为 1
, 如预期。请注意,如果出于某种原因您确实想要
D
包含 A
的两个实例,因此避免使用虚拟继承,您应该使用构造函数的第一个版本。这样,当 d
已构建,d.B::x
和 d.C::x
将设置为 1。感谢转至curiousguy指出虚拟基地实际上是在直接基地之前构建的,而不是我认为的在它们之后。
关于c++ - 类继承 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40181845/