Алмазная проблема - PullRequest
       18

Алмазная проблема

25 голосов
/ 14 января 2010

Википедия по проблеме алмазов:

"... проблема алмазов - это неоднозначность, которая возникает, когда два класса 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();

Ответы [ 2 ]

11 голосов
/ 14 января 2010

Это не та же проблема.

В исходной задаче переопределенный метод можно вызывать из A. В вашей задаче это не может быть так, потому что он не существует.

В проблеме с алмазом конфликт происходит, если класс A вызывает метод Foo. Обычно это не проблема. Но в классе D вы никогда не узнаете, какой экземпляр Foo необходимо вызвать:

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

В вашей проблеме нет общего предка, который может вызывать метод. В классе D есть два варианта Foo, из которых вы можете выбирать, но, по крайней мере, вы знаете, что есть два. И вы можете сделать выбор между ними.

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

Но, как всегда, вам не нужно множественное наследование. Вы можете использовать агрегирование и интерфейсы для решения всех этих проблем.

9 голосов
/ 14 января 2010

В алмазной задаче класс D неявно наследует виртуальный метод от класса A. Чтобы вызвать его, класс D вызовет:

A::foo()

Если оба класса B и C переопределяют этот метод, возникает проблема, которая на самом деле вызывается.

Однако во втором примере это не так, поскольку класс D должен был бы явно состояние, которое называлось:

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

Так что проблемы на самом деле не одинаковы. В проблеме с алмазом вы ссылаетесь не на производные классы, а на их базовый класс, а следовательно, и на неоднозначность.

Вот так я все понимаю.

Обратите внимание, что я пришел из C ++.

...