什么是钻石问题?它是一系列问题还是特定问题?

Posted

技术标签:

【中文标题】什么是钻石问题?它是一系列问题还是特定问题?【英文标题】:What is the Diamond Problem? Is it a family of problems or a specific problem? 【发布时间】:2020-01-21 06:50:02 【问题描述】:

关于下面的示例,哪些结构族和特定错误会受到钻石问题的影响? 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 


【问题讨论】:

【参考方案1】:

菱形问题并不是 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 是一个人(不是两个人),他有两条手臂,两条腿,而不是四条。

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

然后像往常一样 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 继承的。

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

【讨论】:

【参考方案2】:

代码中的 cmets 很好地回答了问题的第一部分。

How does virtual inheritance solve the "diamond" (multiple inheritance) ambiguity?

对于您的函数歧义,我们在 C++ 中有 virtual functions 和 override 关键字

【讨论】:

以上是关于什么是钻石问题?它是一系列问题还是特定问题?的主要内容,如果未能解决你的问题,请参考以下文章

将 Git 挂钩放入存储库

设计模式概述

LeetCode回溯系列——回溯算法讲解

如何获取 Instagram 评论父 ID 并确定它是***还是回复

数据表:它是一次检索所有数据还是在需要时检索所有数据

PTY的品牌好还是梵莎芙品牌好?