c++ - 什么是菱形继承(钻石问题)?它是一系列问题还是特定问题?

标签 c++

关于下面的示例,哪些结构族和特定错误会受到菱形继承(钻石问题)的影响?
Wikipedia 的定义过于笼统,无法在 C++ 的上下文中理解。
特别是,虚拟继承只解决了基类的歧义,而没有解决函数的歧义。

struct A {void func(){}};
struct B: A {void func(){}};
struct C: A {void func(){}};
struct D: B,C {};


struct A2 {void func(){}};
struct B2: virtual A2 {void func(){}};
struct C2: virtual A2 {void func(){}};
struct D2: B2,C2 {};

struct A3 {virtual void func(){}};
struct B3: virtual A3 {void func(){}};
struct C3: virtual A3 {void func(){}};
struct D3: B3,C3 { }; // not ok: func must be overriden

struct A4 {virtual void func(){}};
struct B4:  A4 {void func(){}};
struct C4:  A4 {void func(){}};
struct D4: B4,C4 { }; // not ok: func must be overriden

int main()
{

  A*a = new D; // not ok: ambiguous base A

  A2*a2 = new D2; // ok

  A3*a3 = new D3; // ok

  A4*a4 = new D4; // not ok: ambiguous base A

  D d;
  d.func(); // not ok: ambiguous: candidates are A::func, B::func, C::func

  D2 d2;
  d2.func(); // not ok: ambiguous: B2::func, C2::func 

  D3 d3;
  d3.func(); // not ok: ambiguous: B3::func, C3::func 

  D4 d4;
  d4.func(); // not ok: ambiguous: A4::func, B4::func, C4::func 

}

最佳答案

菱形问题不是 C++ 特有的,它是多重继承中更普遍的问题。这本身不是问题,只是你必须小心的事情。

假设你有这个:

    A
    ^
   / \
  |   |
  B   C
  ^   ^
   \ /
    D

问题是可以用两种不同的方式来解释:
  • 任何 B 都是 A(在那之前没什么特别的)
  • 任何 C 都是 A(也可以)
  • 任何 D 都是 B(小心)
  • 任何 D 都是 C(小心)

  • 对于传递性的最后两个点,您可以说:
  • 任何 D 都是 A(因为任何 B 都是 A)
  • 任何 D 都是 A(因为任何 C 都是 A)

  • 然后:D 是 A 的两倍还是只有一次?这就是菱形继承(钻石问题)。

    现在假设A 有Person,B 有BusinessMan,C 有SportMan,D 有SportAndBusinessMan,你可以同意SportAndBusinessMan 是Person(不是两个Person),他有两条胳膊,两条腿,而不是四条。

    但有时您想使用该图来复制继承的属性。在这种情况下,您会想说:四条腿等。

    然后像往常一样 C++ 没有做出选择,让你选择你想要的。如果你想要第一种情况,这是虚拟继承,第二种情况是传统继承。虚拟继承意味着你只从上面继承一次。
    class A {};
    class B : virtual public A {};
    class C : virtual public B {};
    class D : virtual public B, virtual public C {};
    

    A D 是 A 并且仅继承其属性一次。
    class A { int a; };
    class B : public A {};
    class C : public B {};
    class D : public B, public C {};
    

    A D 是 A 并且继承了它的属性两次,从 B 继承一次,从 C 继承一个,因此两次。然后您自然会产生歧义,您是在谈论从B继承还是从C继承。

    您必须区分类型和继承树路径之间的关系。

    关于c++ - 什么是菱形继承(钻石问题)?它是一系列问题还是特定问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59835571/

    相关文章:

    c++ - 将 Armadillo 中的矩阵从稀疏矩阵转换为密集矩阵(spmat 到 mat)

    c++ - 映射可变参数模板参数

    c++ - std::initializer_list<int>({1,2,3}) 和 {1,2,3} 有什么区别?

    c++ - 我坚持用 C++ 填充我的基于数组的 BST

    c++ - 转发引用始终被视为右值引用

    c++ - 我无法在 C++ 中初始化结构值

    c++ - std::apply 是否应该仅适用于 std::tuple?

    c++ - 无法删除 ListView 中的最后一列?

    c++ - std::vector::push_back 是否有前置条件?

    c++ - 映射中的c++/元素通过退出函数神秘地消失