Виртуальные деструкторы наследованы?

Если у меня есть базовый класс с виртуальным деструктором. Имеет производный класс для объявления виртуального деструктора также?

class base {
public:
    virtual ~base () {}
};

class derived : base {
public:
    virtual ~derived () {} // 1)
    ~derived () {}  // 2)
};

Конкретные вопросы:

  1. 2) 1) и 2) то же? Является 2) автоматически виртуальным из-за его основы, или она "останавливает" виртуальность?
  2. Полученный деструктор может быть опущен, если ему нечего делать?
  3. Какова лучшая практика для объявления полученного деструктора? Объявить это виртуальный, невиртуальный или опустить его если возможный?
75
задан Melebius 6 November 2017 в 10:58
поделиться

4 ответа

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

Небольшое замечание по пункту 3. В комментариях было указано, что если деструктор не объявлен, компилятор генерирует деструктор по умолчанию (который все еще является виртуальным). И эта функция по умолчанию - встроенная.

Встроенные функции потенциально подвергают большую часть вашей программы изменениям в других частях вашей программы и затрудняют двоичную совместимость разделяемых библиотек. Кроме того, усиление связи может привести к частой перекомпиляции перед лицом определенных видов изменений. Например, если вы решите, что вам действительно нужна реализация для вашего виртуального деструктора, тогда каждый фрагмент кода, который его вызвал, необходимо будет перекомпилировать. В то время как если бы вы объявили его в теле класса, а затем определили его пустым в файле .cpp , вы могли бы изменить его без перекомпиляции.

Я по-прежнему предпочитаю опускать его, когда это возможно. На мой взгляд, это загромождает код, и компилятор иногда может делать немного более эффективные вещи с реализацией по умолчанию, а не с пустой.Но есть ограничения, которые могут сделать это плохим выбором.

90
ответ дан 24 November 2019 в 11:42
поделиться

1 / Да 2 / Да, он будет сгенерирован компилятором 3 / Выбор между объявлением его виртуальным или нет должен соответствовать вашему соглашение о переопределении виртуальных членов - ИМХО, есть хорошие аргументы в обе стороны, просто выберите один и следуйте ему.

Я бы пропустил его, если это возможно, но есть одна вещь, которая может побудить вас объявить это: если вы используете сгенерированный компилятором, он неявно встроен. Есть время, когда вы хотите избежать встроенных членов (например, динамических библиотек).

0
ответ дан 24 November 2019 в 11:42
поделиться
  1. Деструктор автоматически становится виртуальным, как и все методы. Вы не можете запретить методу быть виртуальным в C ++ (если он уже был объявлен виртуальным, т. Е. В Java нет эквивалента 'final')
  2. Да, его можно опустить.
  3. Я бы объявил виртуальный деструктор, если я намерен создать подкласс этого класса, независимо от того, является ли он подклассом другого класса или нет, я также предпочитаю продолжать объявлять методы виртуальными, даже если в этом нет необходимости. Это позволит подклассам работать, если вы когда-нибудь решите удалить наследование. Но я полагаю, это просто вопрос стиля.
1
ответ дан 24 November 2019 в 11:42
поделиться

Виртуальная функция-член сделает неявно любую перегрузку этой функции виртуальной.

Таким образом, виртуальный объект в 1) является «необязательным», деструктор базового класса, являющийся виртуальным, делает все дочерние деструкторы виртуальными.

1
ответ дан 24 November 2019 в 11:42
поделиться
Другие вопросы по тегам:

Похожие вопросы: