2010-01-14 19 views
19

Wikipedia sul problema di diamante:diamante Problema

" ... il problema diamante è un'ambiguità che si verifica quando due classi B e C ereditano da A, e la classe D eredita da entrambi B e C. Se un metodo in D chiama un metodo definito in A (e non sovrascrive il metodo), e B e C hanno sovrascritto quel metodo in modo diverso, quindi da quale classe eredita: B o C? "

Così il diamante si presenta così:

A 
/\ 
B C 
\/
    D 

La mia domanda è, cosa succede se non esiste una categoria come ad A, ma ancora una volta B e C dichiarano lo stesso metodo, dicono foo(). Non è lo stesso problema? Perché si chiama così il problema del diamante?

Esempio:

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

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

class D extends B, C { 
} 

new D().foo(); 
+0

quale lingua stai chiedendo? –

+4

@Neil Il linguaggio Butterworth non dovrebbe avere importanza in quanto questo è più un problema di concetto. Lingue come il C++ permettono questo, ma Java e C# no. –

+0

Ed è per questo che "l'ereditarietà multipla" è una parolaccia ... – Danail

risposta

9

La sua non è lo stesso problema.

Nel problema originale, il metodo sovrascritto può essere chiamato da A. Nel tuo problema questo non può essere il caso perché non esiste.

Nel problema del diamante, lo scontro si verifica se la classe A chiama il metodo Foo. Normalmente questo non è un problema. Ma in classe D si può mai sapere quale istanza di Foo deve essere chiamato:

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

Nel tuo problema, non v'è alcun antenato comune che può chiamare il metodo. Sulla classe D ci sono due sapori di Foo tra cui scegliere, ma almeno sai che ce ne sono due. E puoi fare una scelta tra i due.

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

Ma, come sempre, non è necessaria l'ereditarietà multipla. È possibile utilizzare l'aggrifazione e le interfacce per risolvere tutti questi problemi.

+4

L'articolo di Wikipedia parla di chiamare foo() da D, però. E che dire del chiamare foo su una D dall'esterno D come nuovo D(). Foo() (anche nel mio esempio)? – cretzel

6

Nel problema di diamante, classe D eredita implicitamente il metodo virtuale dalla classe A. Per chiamare, classe D chiamerebbe:

A::foo() 

Se entrambe le classi B e C ignorare questo metodo, allora il problema viene di cui viene effettivamente chiamato.

Nel vostro secondo esempio tuttavia, questo non è il caso di classe D avrebbe bisogno di esplicitamente stato che veniva chiamata:

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

Quindi i problemi non sono in realtà la stessa cosa. Nel problema dei diamanti non si fa riferimento alle classi derivate, ma alla loro classe base, quindi all'ambiguità.

Ecco come lo capisco, comunque.

Nota che provengo da uno sfondo C++.

+0

Non conosco il C++, ma non sarebbe lo stesso problema se chiamassi foo da fuori D, dì nuovo D(). Foo()? Quindi l'esempio senza A sarebbe anche problematico, giusto? – cretzel

+0

@cretzel, sì, in questo caso hai anche un problema di conflitto di nomi. –

+0

Penso che nella maggior parte dei casi il compilatore (almeno per C++) darà un errore a causa dell'ambiguità. Ha sui compilatori che ho usato, non sono sicuro di quello che dice lo standard C++ a riguardo. – icabod