c++ - 复杂的菱形继承(钻石问题) : C++ virtual inheritance

标签 c++ multiple-inheritance virtual-inheritance

我有一个看起来像这样的菱形继承(钻石问题):

    __ A
  /    |\
 |  B  |  \
v|/v v\|v  \v
 B2   B3    C
  \v  /v   /
    B4    /
     \   /
       D

我尝试了很多方法来制作最好的虚拟继承来避免重复,但我找不到解决方案。类 A 包含一个位置。这是一个示例输出:

Call: A() position pointer is: 0x2203be8
Call: B()
Call: B2() position pointer is: 0x2203be8
Call: B3() position pointer is: 0x2203be8
Call: C() position pointer is: 0x2203a28
Call: B4() position pointer is: 0x2203be8
Call: D() position pointer is: 0x2203a28

为什么 D 和 C 的位置指针不同?为什么这个 A::position 没有构造函数?我应该做什么样的虚拟继承来解决这个问题?谢谢。

编辑:

这是一个代码示例:

class A;
class B;
class B2 : public virtual B, public virtual A;
class B3 : public virtual B, public virtual A;
class C : public virtual A;
class B4 : public virtual B2, public virtual B3;
class D : public B4, public C;

编辑 2: 为了生成输出,我将这段代码放入每个构造函数中:

A::A()
{
    std::cerr << "Call: A() position pointer is: " << &_position << std::endl;
}

最佳答案

既然你说下面的代码,适用于我的实现,对你来说是坏的,那么显然代码不是问题。问题出在您的设置中;也许是编译器错误。您应该缩小其他可能导致问题的原因;由于代码本身已被排除为问题,因此最好的下一步可能是更新您的编译器。

在任何情况下,这个问题都非常适合您的设置。如果您确实找到了可能适用于其他人的解决方案,那么您应该回来发布它。在那之前,我投票结束这个问题。


我正在尝试重现您的问题。这是我正在使用的代码:

#include <iostream>

struct A { int a; };
struct B { int b; };
struct B2 : virtual B, virtual A {};
struct B3 : virtual B, virtual A {};
struct B4 : virtual B2, virtual B3 {}; // these virtuals are unnecessary in this case...
struct C : virtual A {};
struct D : B4, C {};

int main() {
    D d;
    std::cout << &((B4*)&d)->a << '\n';
    std::cout << &((B3*)(B4*)&d)->a << '\n';
    std::cout << &((B2*)(B4*)&d)->a << '\n';
    std::cout << &((A*)(B2*)(B4*)&d)->a << '\n';
    std::cout << &((A*)(B3*)(B4*)&d)->a << '\n';
    std::cout << &((C*)&d)->a << '\n';
    std::cout << &((A*)(C*)&d)->a << '\n';
}

但我得到的结果与预期的一样,其中 a 成员对于每个对象都是相同的。如果我也在构造函数中使用打印地址,我会得到相同的结果:http://ideone.com/8FdQ1O

如果我稍作改动并从 C 的定义中删除 virtual 关键字:

...
struct C : A {};
...

( version using constructors )

然后我确实看到了您描述的问题,其中 C 拥有自己的 A 子对象,该子对象与 B2、B3 和 B4 使用的虚拟子对象不同。

您确定在所有需要的地方都使用了 virtual 关键字吗?您显示的结果似乎表明您在某处遗漏了它。我还注意到,您显示的输出并不反射(reflect)与您显示的代码片段相同的构造函数顺序;输出首先显示 A(),但代码指示应首先执行 B()。


虚拟继承的工作方式是,最派生类型将包含每个类型的单个虚拟子对象,该对象在继承树中的任何位置虚拟继承。此外,大多数派生类型将包含每个非虚拟继承实例的子对象:

struct A {};
struct B : virtual A {};
struct C : A, B {};
struct D : virtual A, C {};
struct E : A, D {};
struct F : virtual A, E {};
struct G : A, F {};

G g;

g一共包含四个A子对象;每次 A 被非虚拟继承(在 CEG 中),并且一次对于所有时间 A 都是虚拟继承的(在 BDF 中)。

关于c++ - 复杂的菱形继承(钻石问题) : C++ virtual inheritance,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13423012/

相关文章:

c++ - MFC 先处理文件再处理文件夹

c++ - 如何做我自己的自定义运行时错误类?

c++ - cocos2d-x 是否强制多重继承?

C++ 链接时对基类函数的 undefined reference (--不是--vtables、构造函数、模板或纯虚函数)

Java - 用不同的方法实现两个接口(interface)

java - 基本 Java 继承练习

c++ - 虚拟继承如何解决 "diamond"(多重继承)的歧义?

c++ - 当基类不包含数据成员时是否仍然需要虚拟继承?

java - C++中Java接口(interface)的等价物?

c++ - 将几个依赖的 C++ makefile 项目移植到 MSVC 中