钻石问题

时间:2010-01-14 14:46:54

标签: oop inheritance diamond-problem

关于钻石问题的维基百科:

“......当两个B和C类继承自A,而D类继承自B和C时,钻石问题就会产生歧义。如果D中的方法调用A中定义的方法(并且不覆盖方法),B和C以不同方式覆盖该方法,然后从哪个类继承:B或C?“

所以钻石看起来像这样:

  A
 / \
B   C
 \ /
  D

我的问题是,如果没有这样的A类会发生什么,但B和C再次声明相同的方法,比如说foo()。这不是同一个问题吗?为什么它被称为钻石问题?

示例:

class B {
    public void foo() {...}
}

class C {
    public void foo() {...}
}

class D extends B, C {
}

new D().foo();

3 个答案:

答案 0 :(得分:11)

它不是同一个问题。

在原始问题中,可以从A调用overriden方法。在您的问题中,情况并非如此,因为它不存在。

在钻石问题中,如果A类调用方法Foo,则会发生冲突。通常这没问题。但是在D类中你永远无法知道需要调用哪个Foo实例:

         +--------+
         |   A    |
         | Foo    |
         | Bar    |
         +--------+
            /  \
           /    \
          /      \
+--------+        +--------+
|   B    |        |   C    |
| Foo    |        | Foo    |
+--------+        +--------+
          \      /
           \    /
            \  /
         +--------+
         |   D    |
         |        |
         +--------+

在您的问题中,没有可以调用该方法的共同祖先。在D级,你可以选择两种Foo,但至少你知道有两种。你可以在两者之间做出选择。

+--------+        +--------+
|   B    |        |   C    |
| Foo    |        | Foo    |
+--------+        +--------+
          \      /
           \    /
            \  /
         +--------+
         |   D    |
         |        |
         +--------+

但是,与往常一样,您不需要多重继承。您可以使用aggegration和接口来解决所有这些问题。

答案 1 :(得分:9)

在钻石问题中,D类隐式继承了A类中的虚方法。要调用它,D类会调用:

A::foo()

如果B和C类都覆盖了这个方法,那么实际上会调用问题。

然而,在你的第二个例子中,情况并非如此,因为D类需要明确 被称为的州:

B::foo()
C::foo()

所以问题实际上并不相同。在钻石问题中,您没有引用派生类,而是它们的基类,因此模棱两可。

无论如何,这就是我的理解。

请注意,我来自C ++背景。

答案 2 :(得分:0)

您的第二个示例远没有解决钻石问题,因为编译器能够检测继承一级的可用函数。

一旦编译器知道您在两个基类中使用的是同名函数,它将抛出error: member 'foo' found in multiple base classes of different types