Алмазная проблема
-
20-09-2019 - |
Вопрос
Википедия по проблеме алмазов:
"...проблема алмаза - это двусмысленность, которая возникает, когда два класса B и C наследуют от A, а класс D наследует как от B, так и От C.Если метод в D вызывает метод, определенный в A (и не переопределяет метод), а 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();
Решение
Это не та же самая проблема.
В исходной задаче переопределенный метод может быть вызван из A.В вашей проблеме этого не может быть, потому что этого не существует.
В задаче с алмазом столкновение происходит, если класс A вызывает метод Foo.Обычно это не проблема.Но в классе D вы никогда не можете знать, какой экземпляр Foo нужно вызвать:
+--------+
| A |
| Foo |
| Bar |
+--------+
/ \
/ \
/ \
+--------+ +--------+
| B | | C |
| Foo | | Foo |
+--------+ +--------+
\ /
\ /
\ /
+--------+
| D |
| |
+--------+
В вашей проблеме нет общего предка, который мог бы вызвать этот метод.В классе D есть два вкуса Foo, из которых вы можете выбрать, но, по крайней мере, вы знаете, что их два.И вы можете сделать выбор между этими двумя.
+--------+ +--------+
| B | | C |
| Foo | | Foo |
+--------+ +--------+
\ /
\ /
\ /
+--------+
| D |
| |
+--------+
Но, как всегда, вам не нужно множественное наследование.Вы можете использовать интеграцию и интерфейсы для решения всех этих проблем.
Другие советы
В задаче Diamond класс D неявно наследует виртуальный метод от класса A.Чтобы вызвать его, класс D вызвал бы:
A::foo()
Если оба класса B и C переопределяют этот метод, то возникает проблема, из-за которой на самом деле вызывается.
Однако в вашем втором примере это не так, поскольку классу D потребуется явно указать состояние, которое вызывалось:
B::foo()
C::foo()
Так что проблемы на самом деле не те же самые.В задаче diamond вы ссылаетесь не на производные классы, а на их базовый класс, отсюда и двусмысленность.
Во всяком случае, так я это понимаю.
Обратите внимание, что я исхожу из опыта работы с C ++.