2010-01-14 23 views
19

Wikipedia na problemie diamentowe:Diament Problem

”... problem diament jest wieloznaczność, która powstaje, gdy dwie klasy B i C dziedziczą z A i klasy D dziedziczy zarówno B i C. Jeśli metoda w D wywołuje metodę zdefiniowaną w A (i nie zastępuje metody), a B i C nadpisały tę metodę w inny sposób, a następnie od której klasy dziedziczy ona: B lub C? "

Więc diament wygląda następująco:

A 
/\ 
B C 
\/
    D 

Moje pytanie brzmi, co się stanie, jeśli nie ma takiej klasy A, ale znowu B i C deklaruje sam sposób, powiedzmy foo(). Czy to nie jest ten sam problem? Dlaczego nazywa się to problemem diamentowym?

przykład:

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

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

class D extends B, C { 
} 

new D().foo(); 
+0

o jaki język pytasz? –

+4

@Neil Butterworth język nie powinno mieć znaczenia w tym, ponieważ jest to bardziej problem koncepcji. Języki takie jak C++ pozwalają na to, ale Java i C# nie. –

+0

I właśnie dlatego "wielokrotne dziedziczenie" jest brudnym słowem ... – Danail

Odpowiedz

9

Nie jest to ten sam problem.

W oryginalnym problemie, metoda overriden może zostać wywołana z A. W twoim problemie to nie może być, ponieważ nie istnieje.

W przypadku problemu z diamentem zderzenie ma miejsce, jeśli klasa A wywoła metodę Foo. Zwykle nie stanowi to problemu. Ale w klasie D nigdy nie można wiedzieć, które instancja Foo musi się nazywać:

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

W problemu, nie ma wspólnego przodka, który może wywołać metodę. W klasie D są dwa smaki Foo, z których możesz wybierać, ale przynajmniej wiesz, że są dwa. I możesz dokonać wyboru między tymi dwoma.

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

Ale, jak zwykle, nie potrzebujesz wielokrotnego dziedziczenia. Możesz użyć agegracji i interfejsów, aby rozwiązać wszystkie te problemy.

+4

Artykuł w Wikipedii mówi jednak o wywołaniu foo() z D. A co z wywołaniem foo na D z zewnątrz D jak nowy D(). Foo() (również w moim przykładzie)? – cretzel

6

W problemu diamentowej, klasa D niejawnie dziedziczy metodę wirtualną z klasy A. nazwać, klasa D nazwałbym:

A::foo() 

przypadku obu klas B i C zastąpić tę metodę, to problem jest z których faktycznie zostaje wywołana.

W swoim drugim przykładzie jednak nie jest to przypadek, jak klasy D musiałby wyraźnie stan, który był nazywany:

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

więc problemy nie są w rzeczywistości takie same. W problemie z diamentem nie odwołujesz się do klas pochodnych, ale do ich klasy bazowej, a więc do niejednoznaczności.

Tak to rozumiem.

Zauważ, że pochodzę z tła w C++.

+0

Nie znam C++, ale czy nie byłby to ten sam problem, gdybyś zadzwonił do foo z zewnątrz D, powiedzmy nowego D(). Foo()? Wtedy przykład bez A również byłby problematyczny, prawda? – cretzel

+0

@cretzel, tak, w takim przypadku masz także problem z nazwą. –

+0

Myślę, że w większości przypadków kompilator (przynajmniej dla C++) spowoduje błąd z powodu niejasności. Ma na kompilatorach, których używałem, nie jestem pewien, co mówi o tym standard C++. – icabod