2010-01-14 152 views
19

維基百科上的金剛石問題:鑽石問題

」 ...金剛石的問題是,當出現兩個類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

你問什麼語言? – 2010-01-14 14:49:18

+4

@Neil Butterworth語言不應該在這個問題上,因爲這更多的是一個概念問題。像C++這樣的語言允許這樣做,但Java和C#不支持。 – 2010-01-14 14:50:11

+0

這就是爲什麼「多重繼承」是一個髒話...... – Danail 2010-01-14 15:01:15

回答

9

它不是同樣的問題。

在原始問題中,可以從A中調用overriden方法。在您的問題中,情況並非如此,因爲它不存在。

在鑽石問題中,如果A類調用方法Foo,則會發生衝突。通常這是沒有問題的。但在d類,你可以永遠不知道它的Foo實例需要調用:

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

在你的問題,有沒有共同的祖先,可以調用該方法。在D課上,你可以選擇兩種口味的Foo,但至少你知道有兩種口味。你可以在兩者之間做出選擇。

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

但是,一如既往,您不需要多重繼承。您可以使用aggegration和接口來解決所有這些問題。

+4

雖然維基百科的文章談到了從D調用foo()的問題。 那麼從外部D調用foo就像新的D()。foo()(在我的例子中)呢? – cretzel 2010-01-14 15:16:05

6

在鑽石的問題,類d隱含繼承類A.虛擬方法來調用它,類d稱之爲:

A::foo() 

如果兩個B級和C重寫此方法,那麼問題就來了其中實際上被調用。

在你的第二個例子然而,這並非如此,因爲d類都需要這是被稱爲明確 狀態:

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

所以問題實際上並不相同。在鑽石問題中,你並沒有引用派生類,而是它們的基類,因此不明確。

這就是我的理解,無論如何。

請注意,我來自C++背景。

+0

我不知道C++,但是如果你從D之外調用foo,說出新的D()。foo(),它不會是同樣的問題嗎?那麼沒有A的例子也會有問題,對吧? – cretzel 2010-01-14 15:01:23

+0

@ secretzel,是的,在這種情況下,你也有名稱衝突問題。 – 2010-01-14 15:10:55

+0

我認爲在大多數情況下,由於含糊不清,編譯器(至少用於C++)會出錯。它對我使用的編譯器有用,我不確定C++標準對此有何評論。 – icabod 2010-01-14 15:17:56