... Обратите внимание, Херб Саттер написал 3 отличные статьи о множественном наследовании (1) здесь , (2) здесь и (3) здесь . Он написал целую кучу полезных статей в "Гуру недели" здесь . Настоятельно рекомендуется ...
Во-первых, я не уверен, что правильно понял вашу иерархию. Я так понимаю, это так:
struct A {
virtual void F() = 0;
};
struct B : A { void F() { } };
struct C : A { };
struct D : B, C { };
Что ж, D является абстрактным, потому что в объекте типа D есть два A
подобъекта: один, который конкретизируется B
через решетку B, и тот, который все еще является абстрактным в решетке, проходящей через C
. Я так понимаю, у вас есть указатель на D
и попробуйте позвонить F
. Да, возникает неоднозначность, потому что компилятор находит две функции F
в двух отдельных решетках:
D -> B::F
D -> C -> A::F
выглядит так:
F() F()
A A
| |
F() B C
\ /
D
Вы можете исправить эту ситуацию формально, фактически получая из A:
struct B : virtual A { void F() { } };
struct C : virtual A { };
struct D : B, C { };
У вас возникает такая ситуация, которая называется наследованием алмазов:
F()
A
/ \
F() B C
\ /
D
И, выполняя поиск, он обнаруживает, что B::F
переопределяет A::F
. Хотя A::F
все еще может быть достигнуто через D::C::A
, это больше не двусмысленность, потому что A
был унаследован виртуально.
Является ли это правильным решением в вашей конкретной проблеме - это, конечно, не ясно. Чаще всего есть лучшие способы, чем вывод виртуального из класса. На ваш вопрос о слиянии таблиц виртуальных функций - это полностью зависит от реализации. GCC
, насколько я знаю, будет хранить указатель на один экземпляр A в виртуальной таблице D
, если мы получим виртуальный.