关于钻石问题的维基百科:
“......当两个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();
答案 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
。