Без virtual объект D содержит две независимые части A. Доступ obj.value неоднозначен; можно выбрать ветвь явно, но это не объединяет два значения в одно.
Реализация множественного наследования без применения virtual и его последствия
Без virtual объект D содержит две независимые части A. Доступ obj.value неоднозначен; можно выбрать ветвь явно, но это не объединяет два значения в одно.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо показать, как построить иерархию классов с множественным наследованием, не используя ключевое слово virtual, а затем описать, к каким проблемам это приводит.
struct A {
int value;
};
struct B : A { };
struct C : A { };
struct D : B, C { };
int main() {
D obj;
// доступ к полю value здесь неоднозначен
// obj.value; → ошибка компиляции
return 0;
}
В данном примере класс D наследует от B и C, а те, в свою очередь, наследуют от A. Поскольку virtual не используется, в объекте D присутствуют два независимых под‑объекта A, и попытка обратиться к полю value становится неоднозначной, что приводит к ошибке компиляции. Нужно объяснить, как виртуальное наследование устраняет эту проблему и какие дополнительные затраты оно влечёт.
Ответ
Без virtual объект D содержит две независимые части A. Доступ obj.value неоднозначен; можно выбрать ветвь явно, но это не объединяет два значения в одно.
Например, obj.B::value = 1; и obj.C::value = 2; изменяют разные поля. Преобразование D* напрямую в A* тоже неоднозначно; нужно выбрать B или C.
Если нужен единый A, объявите struct B : virtual A {}; и struct C : virtual A {};. Тогда общую базу конструирует самый производный D. Реализация обычно требует служебной информации и косвенного вычисления смещения, но конкретные размеры и расходы стандарт не фиксирует.