Виртуальное наследование необходимо для исключений?
Я понимаю необходимость виртуального наследования при использовании множественного наследования - это решает проблему Dreaded Diamond.
Но что, если я не использую множественное наследование? Есть ли необходимость в виртуальном наследовании вообще?
Кажется, я помню, что слышал, что это было важно для исключений (выбросить производный класс, поймать по ссылке на базовый класс) Но разве виртуальных деструкторов не достаточно для этого?
Я пытался найти справочную страницу, которую я когда-то видел на этом, но я не могу найти ее.
5 ответов
Вы, вероятно, думаете об этом руководстве Boost.Exception, которое я напишу здесь для полноты:
Использование виртуального наследования в типах исключений
Типы исключений должны использовать виртуальное наследование при наследовании от других типов исключений. Это понимание связано с Эндрю Кениг. Использование виртуального наследования предотвращает проблемы неоднозначности в обработчике исключений:
#include <iostream>
struct my_exc1 : std::exception { char const* what() const throw(); };
struct my_exc2 : std::exception { char const* what() const throw(); };
struct your_exc3 : my_exc1, my_exc2 {};
int
main()
{
try { throw your_exc3(); }
catch(std::exception const& e) {}
catch(...) { std::cout << "whoops!" << std::endl; }
}
Программа выше выводит "упс!" потому что преобразование в std::exception является неоднозначным.
Накладные расходы, вносимые виртуальным наследованием, всегда незначительны в контексте обработки исключений. Обратите внимание, что виртуальные базы инициализируются непосредственно конструктором самого производного типа (тип, передаваемый в оператор throw, в случае исключений.) Однако обычно эта деталь не имеет значения, когда используется boost:: exception, потому что это позволяет типам исключений быть тривиальными структурами без элементов (нечего инициализировать). См. Типы исключений как простые семантические теги.
Да, если ваши классы исключений предполагают множественное наследование.
Единственная стоимость виртуального наследования - это vtable, который не так уж и затратен. Использование виртуального наследования означает, что после того, как люди наследуют от разных вещей, проблема двойного алмаза не будет неожиданно поднимать их уродливую голову. Это просто означает, что ваш класс станет хорошим базовым классом.
Нет, это не нужно, кроме как решить проблему с бриллиантами. Вы должны воображать вещи!
Я понимаю необходимость виртуального наследования при использовании множественного наследования - это решает проблему Dreaded Diamond.
Но что, если я не использую множественное наследование?
Вопрос (в основном риторический): Откуда вы знаете, что МИ никогда не будет использоваться?
Ответ: Вы не можете этого знать. (Пока ты не докажешь.)
Кажется, я помню, что слышал, что это было важно для исключений (выбросить производный класс, поймать по ссылке на базовый класс). Но разве виртуальных деструкторов не достаточно для этого?
Вопрос (риторический): зачем здесь нужен виртуальный деструктор?
Ответ: это не так.