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

  • 本文关键字:问题 一系列 钻石 c++
  • 更新时间 :
  • 英文 :


关于下面的示例,哪些结构族和特定错误受到钻石问题的影响? 维基百科的定义过于笼统,无法在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有人,B是商人,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 {};

D 是 A,只继承其属性一次。

class A { int a; };
class B : public A {};
class C : public B {};
class D : public B, public C {};

A 是 A,继承其属性两次,从 B 继承一次,从 C 继承一次,因此两次。然后你自然会有一个歧义,你说的是 A 继承自 B 还是从 C 继承的。

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

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

虚拟继承如何解决"钻石"(多重继承(歧义?

对于您的函数歧义,我们在C++中提供了虚拟函数和覆盖关键字