2012-05-28 32 views

回答

3

如果你繼承兩種方法從不同類別相同的簽名,在調用此方法時有歧義。它可以被解決,但它可以說是一個混亂的情況。

如果您實現用同樣的方法簽名兩個接口,也不要緊,因爲還只是一個實現從調用該方法時進行選擇。

The diamond problem是上述的問題,這使得情況變得混亂的延伸。當限制多重繼承到接口時,這個問題基本上消失了。

0

也許是因爲粒度的:你可以選擇哪些接口的類實現。而如果擴展一個類,則會自動繼承整個類的層次結構。

+1

但是,在實現接口時,您會自動獲得接口的整個層次結構。 – aioobe

+0

是的,但它們只是簽名:P – maksimov

+0

是的。但你的回答是誤導。 – aioobe

0

兩個可能的原因: 1.)鑽石問題(請看維基百科), 2.)對象身份。

class A { } 
class B { } 
class C : A, B { } 

C * c = new C(); 
A * a = c; 
B * b = c; 

然後,您不能通過簡單地測試== b來驗證對象身份。如果試圖在語言來實現此功能,您不能在後臺使用簡單的指針運算,這樣訪問類(獨立muliple繼承)變得更加昂貴,因爲A和B不是普通的指針了。

如果A和B都是接口,你瞭解這個問題,(你知道,他們將繼承),這樣你可以從訪問類區別對待訪問接口。

順便說一句:多個類的繼承不是難以實現。

編輯:加法。它介紹了概念上的問題:

class C0 { virtual int meth { return 0; } }; 
class C1 : C0 { virtual int meth { return 1; } }; 
class C2 : C1, C0 { } 

如果我們定義

C2 * c2 = new C2; 

我應該

((C1 *) c2)->meth() 

((C0 *) c2)->meth() 

回報爲了不讓人混淆? (編輯:更正本示例)

+0

關於你的後一個問題,我看不出含糊不清;第一個調用應該返回1,後者調用0。如果兩個類'C1a'和'C1b'繼承一個公共基類'C0'並覆蓋相同的虛擬成員'f',另一個類'C2'返回一個問題。從這兩者繼承。如果upcasts必須一次執行一個級別(例如給定'C2 it',那麼不能只是說'(C0)它',而必須說'(C0)(C1a)它或'(C0) (C1b)它可以解決歧義,但是(C0)(C1a)it'和'(C0)(C1b)it'將表現爲不同類型的對象或不同的對象。 – supercat

+0

對不起,我的例子被設置爲sloppily(無指針)。然而,我確實看到了概念上的問題,因爲你可以爲'(C0 *)c2-> meth()'返回0(因爲'C2'直接從'C0'繼承,'C2'沒有定義'meth'') ,並且不清楚爲什麼當轉換爲C0時,爲什麼「class C2:C1,C0」應該與「class C2:C0」不同,或者你可以爭辯爲1(因爲'(C0 *)(C1 * )c2'不應該和'(C0 *)c2'不同) – JohnB

+0

如果一種語言自由地支持多重繼承,我看不到任何方式來保持'(TFinalType)(TIntermediate1)事物'的等同性到'(TFinalType)(TIntermediate2)事物',在所有情況下,這兩個表達式都是格式良好的,只能使用upcasts或self-casts。因此,我看不到任何避免乘法繼承類類型只能被轉換爲它的直接超類型,並且一個上傳必須被認爲是「直接的」。因爲C0是C2的直接超類型,所以該類型應該被認爲不通過C1。 – supercat

0

如至少在.NET指出的,接口的方法是僅在其被聲明爲的,或限制爲目的,接口類型可用。因此,如果C1有方法Foo,並且還實現了接口Intf1Intf2,每個聲明的方法Foo,那麼在大多數情況下,存在一個名爲Foo三種方法都不會有問題,因爲他們會在什麼是存在的事實基本上分開的域。

此外,如果接口IDerived1IDerived2和繼承IBase,其包括構件Foo,其實現兩個接口類,或它繼承兩個接口的接口,將剛剛定義的IBase.Foo一個定義。 IDerived1,IDerived2和/或來自兩者的接口聲明他們自己的Foo成員將是可能的,但是任何這樣的定義將與IBase.Foo完全分開。將派生接口投射到IBase並在其上調用Foo總是會產生相同的IBase.Foo方法,無論是直接投射到IBase還是先投射到其他接口。相比之下,如果一個類派生自另外兩個類,它們都會覆蓋同一個基類的同一個成員,但是如果將派生類的對象轉換爲基類並嘗試使用該成員。

順便說一句,有一些情況可能會出現歧義。如果一個接口繼承兩個具有相同名稱成員的接口,則可能需要使用一些技巧來強制編譯器相對於另一個接口,或者讓派生接口添加自己的同名成員,這會影響兩個原件。另外,使用泛型時,可以限制泛型類型來實現多個接口,並且也可以從類繼承。完成此操作後,如果接口和/或類共享成員名稱,則存在模糊的可能性。