Ответ 1
- Да, они одинаковы. Производный класс, не объявляющий что-то виртуальное, не мешает ему быть виртуальным. На самом деле нет способа остановить использование любого метода (включенного деструктора) из виртуального в производном классе, если он был виртуальным в базовом классе. В >= С++ 11 вы можете использовать
final
, чтобы предотвратить его переопределение в производных классах, но это не мешает ему быть виртуальным. - Да, деструктор в производном классе может быть опущен, если ему нечего делать. И не имеет значения, действительно ли его виртуальный.
- Я бы опустил это, если возможно. И я всегда использую ключевое слово
virtual
снова для виртуальных функций в производных классах по соображениям ясности. Людям не нужно идти по иерархии наследования, чтобы выяснить, что функция виртуальна. Кроме того, если ваш класс может быть скопирован или перемещен без необходимости объявления вашей собственной копии или перемещения конструкторов, объявление деструктора любого типа (даже если вы определяете его какdefault
) заставит вас объявить копию и переместить конструкторы и операторы присваивания если вы хотите их, поскольку компилятор больше не будет их вводить для вас.
В качестве небольшой точки для пункта 3. В комментариях было указано, что если деструктор не объявлен, компилятор генерирует значение по умолчанию (которое по-прежнему является виртуальным). И это значение по умолчанию - встроенная функция.
Встроенные функции потенциально могут привести к большей части вашей программы изменениям в других частях вашей программы и сделать двоичную совместимость для общих библиотек сложной. Кроме того, повышенная связь может привести к перекомпиляции перед лицом определенных видов изменений. Например, если вы решите, что действительно хотите реализовать свой виртуальный деструктор, тогда каждый фрагмент кода, который его вызвал, нужно будет перекомпилировать. Если вы объявили его в теле класса, а затем определили его пустым в файле .cpp
, вы могли бы его изменить без перекомпиляции.
Мой личный выбор по-прежнему заключался бы в том, чтобы опустить его, когда это возможно. По-моему, он загромождает код, и компилятор иногда может делать несколько более эффективные вещи с реализацией по умолчанию по пустой. Но есть ограничения, с которыми вы можете столкнуться, что это плохой выбор.