Об устройстве памяти
В качестве примечания, проблема с Dreaded Diamond заключается в том, что базовый класс присутствует несколько раз. Таким образом, при регулярном наследовании вы верите:
A
/ \
B C
\ /
D
Но в макете памяти у вас есть:
A A
| |
B C
\ /
D
Это объясняет, почему при звонке D::foo()
возникает проблема неоднозначности. Но проблема real возникает, когда вы хотите использовать переменную-член A
. Например, скажем, у нас есть:
class A
{
public :
foo() ;
int m_iValue ;
} ;
Когда вы попытаетесь получить доступ к m_iValue
из D
, компилятор будет протестовать, потому что в иерархии он увидит два m_iValue
, а не одно. И если вы измените один, скажем, B::m_iValue
(то есть родительский элемент A::m_iValue
для B
), C::m_iValue
не будет изменен (это родительский A::m_iValue
C
).
Здесь виртуальное наследование пригодится, так как с его помощью вы вернетесь к истинной алмазной раскладке, используя не только один метод foo()
, но также один и только один m_iValue
.
Что может пойти не так?
Представьте себе:
A
имеет некоторые основные функции.
B
добавляет к этому какой-то классный массив данных (например)
C
добавляет к нему некую классную функцию, например, шаблон наблюдателя (например, на m_iValue
).
D
наследуется от B
и C
и, следовательно, от A
.
При обычном наследовании изменение m_iValue
из D
является неоднозначным, и это должно быть решено. Даже если это так, внутри D
есть два m_iValues
, так что лучше запомните это и обновите их одновременно.
С виртуальным наследованием изменение m_iValue
из D
в порядке ... Но ... Допустим, у вас есть D
. Через интерфейс C
вы подключили наблюдателя. А через интерфейс B
вы обновляете классный массив, побочным эффектом которого является прямое изменение m_iValue
...
Поскольку изменение m_iValue
выполняется напрямую (без использования метода виртуального средства доступа), наблюдатель, «прослушивающий» через C
, вызываться не будет, поскольку код, реализующий прослушивание, находится в C
, и B
не знает об этом ...
Заключение
Если у вас есть ромб в вашей иерархии, это означает, что у вас есть 95%, чтобы сделать что-то не так с указанной иерархией.