一个类继承c++
A class inheritance C++
我有一个关于类继承的问题。
我想下面的代码可以解释我的问题:
struct A {
int x;
};
struct B: A {
};
struct C: A {
};
struct D: B, C {
D() : x(1) {}
};
int main() {
D d;
}
代码无法编译。
问题是:如何创建结构体D的实例?谢谢!
你要做的有两个问题。
-
D
没有一个成员x
,它有两个成员x
。具体来说,D::B::x
和D::C::x
由于多重继承而存在一定的问题,称为菱形问题。由于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 +---
-
类只能在成员初始化器列表中初始化自己的成员;不允许初始化其基类的成员。这是因为c++中的对象是分步骤构造的:
- 首先,构造继承层次结构中任何地方遇到的虚基。派生最多的类被认为负责它们的构造。如果派生最多的类在其初始化列表中提到了它的虚基类,则该虚基类将被传递指定的形参。如果任何直接基类在它们的初始化列表中提到任何虚基类,它将被忽略。然后,构造对象的直接基类(如果有的话)。对象构造规则是递归地应用的,这意味着首先构造派生最少的类(即位于继承层次结构最底层的类)。如果直接基类具有虚基类,则此时不会构造该虚基类。[如果派生类在初始化列表中提到它的任何直接基类,那么该基类将被传递指定的参数]
- 最后,派生类是围绕它的直接基类构造的,然后是它的虚基类。此时构造非静态数据成员;如果在初始化器列表中,它们将使用指定的参数构造,否则将默认构造。
因此,
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; }
它的成员
d.x
现在将被设置为1
。注意,如果出于某种原因确实希望
D
包含A
的两个实例,从而避免使用虚拟继承,则应该使用构造函数的第一个版本。这样,当构建d
时,d.B::x
和d.C::x
都将被设置为1。
感谢curousguy指出虚拟基地实际上是在直接基地之前构建的,而不是像我认为的那样在它们之后。
相关文章:
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 混合组合和继承的C++问题
- 继承:构造函数,初始化C++11中基类的类C数组成员
- 从类继承时,继承的类是否会通过父类重新定义继承的变量
- 公共与私人继承
- 如何创建从同一类继承的不同对象的向量
- 如何从另一个文件继承私有成员变量和公共函数
- 在模板基类中为继承类中的可选重写生成虚拟方法
- 带有继承的C++工厂
- 我应该避免多重实现继承吗
- C++继承更改成员
- 从具有默认值的部分指定模板类继承时发生SWIG错误,具有不带默认值的正向声明
- 关于C++中具有多重继承"this"指针的说明
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 如何在QT Creator上将QWidget声明为继承类的对象