2010-01-14 9 views
19

Wikipédia sur le problème du diamant:diamant Problème

» ... le problème de diamant est une ambiguïté qui se pose lorsque deux classes B et C de A hériteront, et la classe D hérite à la fois B et C. Si une méthode dans D appelle une méthode définie dans A (et ne remplace pas la méthode), et B et C ont surchargé cette méthode différemment, puis de quelle classe hérite-t-il: B ou C? "

Ainsi, le diamant ressemble à ceci:

A 
/\ 
B C 
\/
    D 

Ma question est, ce qui se passe s'il n'y a pas de classe A, mais encore une fois B et C déclarent la même méthode, dire foo(). N'est-ce pas le même problème? Pourquoi est-ce alors appelé problème de diamant?

Exemple:

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

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

class D extends B, C { 
} 

new D().foo(); 
+0

quelle langue demandez-vous? –

+4

@Neil Le langage Butterworth ne devrait pas avoir d'importance dans ce domaine car il s'agit davantage d'un problème de concept. Des langages comme C++ le permettent mais pas Java et C#. –

+0

Et c'est pourquoi "l'héritage multiple" est un mot sale ... – Danail

Répondre

9

Ce ne est pas le même problème.

Dans le problème d'origine, la méthode substituée peut être appelée à partir de A. Dans votre problème, cela ne peut pas être le cas car il n'existe pas.

Dans le problème de diamant, le conflit se produit si la classe A appelle la méthode Foo. Normalement, ce n'est pas un problème. Mais en classe D, vous ne pouvez jamais savoir quelle instance de Foo doit être appelée:

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

Dans votre problème, il n'y a aucun ancêtre commun qui peut appeler la méthode. Sur la classe D, vous pouvez choisir parmi deux saveurs de Foo, mais au moins vous savez qu'il y en a deux. Et vous pouvez faire un choix entre les deux.

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

Mais, comme toujours, vous n'avez pas besoin d'héritage multiple. Vous pouvez utiliser l'aggegration et les interfaces pour résoudre tous ces problèmes.

+4

L'article de Wikipedia parle d'appeler foo() de D, cependant. Et qu'en est-il d'appeler foo sur un D de l'extérieur D comme new D(). Foo() (aussi dans mon exemple)? – cretzel

6

Dans le problème de diamant, classe D hérite implicitement la méthode virtuelle de la classe A. Pour appeler, classe D appellerait:

A::foo() 

Si les classes B et C remplacer cette méthode, le problème vient dont il est appelé.

Dans votre deuxième exemple cependant, ce n'est pas le cas en tant que classe D aurait besoin explicitement état qui a été appelé:

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

Ainsi, les problèmes ne sont pas en fait le même. Dans le problème du diamant, vous ne faites pas référence aux classes dérivées, mais à leur classe de base, d'où l'ambiguïté.

C'est ainsi que je le comprends, de toute façon.

Notez que je viens d'un arrière-plan C++.

+0

Je ne connais pas le C++, mais ne serait-ce pas le même problème si vous appeliez foo de l'extérieur de D, disons nouveau D(). Foo()? Alors l'exemple sans A serait aussi problématique, non? – cretzel

+0

@cretzel, oui, dans ce cas, vous avez aussi un problème de conflit de nom. –

+0

Je pense que dans la plupart des cas, le compilateur (pour C++ au moins) donnera une erreur en raison de l'ambiguïté. Il a sur les compilateurs que j'ai utilisés, je ne suis pas sûr de ce que le standard C++ en dit. – icabod