gpt4 book ai didi

c++ - 类继承 C++

转载 作者:行者123 更新时间:2023-12-02 11:15:35 24 4
gpt4 key购买 nike

我有一个关于类继承的问题。

我认为以下代码将解释我的问题:

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::xD::C::x , 由于多重继承和称为 diamond problem 的某个问题.作为BC来自 A ,它们每个都包含 A 的全部内容在他们的定义中,因此每个都包含自己的A::x .所以,当 D源自 BC , 它包含一个完整的 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
    | | +---
    | +---
    +---

    您应该改为修改 BC从 A 虚拟继承,如:
    struct B: virtual A {
    };

    struct C: virtual A {
    };

    这将导致 BC到,而不是包含它们的基数 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
    +---
  • 一个类只能在 member initialiser list 中初始化它自己的成员。 ;不允许初始化其基类的成员。这是因为 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;
    }

    其成员(member) d.x现在将设置为 1 , 如预期。

    请注意,如果出于某种原因您确实想要 D包含 A 的两个实例,因此避免使用虚拟继承,您应该使用构造函数的第一个版本。这样,当 d已构建, d.B::xd.C::x将设置为 1。

    感谢转至 curiousguy指出虚拟基地实际上是在直接基地之前构建的,而不是我认为的在它们之后。

    关于c++ - 类继承 C++,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40181845/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com