Россия и Беларусь начали и продолжают войну против народа Украины!

Урок №165. Виртуальные деструкторы и Виртуальное присваивание

  Юрий  | 

  |

  Обновл. 15 Сен 2021  | 

 40605

 ǀ   7 

Хотя язык C++ автоматически предоставляет деструкторы для ваших классов, если вы не предоставляете их самостоятельно, все же иногда вы можете сделать это сами.

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

При работе с наследованием ваши деструкторы всегда должны быть виртуальными. Рассмотрим следующий пример:

Поскольку parent является указателем класса Parent, то при его уничтожении компилятор будет смотреть, является ли деструктор класса Parent виртуальным. Поскольку это не так, то компилятор вызовет только деструктор класса Parent.

Результат выполнения программы:

Calling ~Parent()

Тем не менее, нам нужно, чтобы delete вызывал деструктор класса Child (который, в свою очередь, будет вызывать деструктор класса Parent), иначе m_array не будет удален. Это можно выполнить, сделав деструктор класса Parent виртуальным:

Результат выполнения программы:

Calling ~Child()
Calling ~Parent()

Правило: При работе с наследованием ваши деструкторы должны быть виртуальными.

Виртуальное присваивание


Оператор присваивания можно сделать виртуальным. Однако, в отличие от деструктора, виртуальное присваивание не всегда является хорошей идеей. Почему? Это уже выходит за рамки этого урока. Следовательно, для сохранения простоты в вашем коде, не рекомендуется использовать виртуальное присваивание.

Игнорирование виртуальных функций

В языке С++ мы можем игнорировать вызов переопределений. Например:

Здесь мы хотим, чтобы ссылка класса Parent на объект класса Child вызывала Parent::getName() вместо Child::getName(). Чтобы это сделать, нужно просто использовать оператор разрешения области видимости:

Вы, скорее всего, не будете использовать это очень часто, но знать об этом стоит.


Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (187 оценок, среднее: 4,84 из 5)
Загрузка...

Комментариев: 7

  1. Константин:

    Однако, в отличие от деструктора, виртуальное присваивание не всегда является хорошей идеей. Почему? Это уже выходит за рамки этого урока.

    Хотелось бы поподробнее узнать, о причинах или получить ссылку на источник, где рассказано об этом, так как уже было с выравниванием данных, а тут просто сказали "это плохо, всё идём дальше", без объяснения причин.

  2. Сергей:

    Не совсем понятно зачем делать деструктор класса Child виртуальным.
    В данном примере у него нет наследников.

    1. Aleksandr:

      Если тут как с методами, то деструктор класса-наследника будет неявно виртуальным, так как является переопределением виртуального деструктора в классе-родителе, ключевое слово указывается, чтобы не забыть это.

  3. Алексей:

    Строго говоря, при удалении наследника при помощи delete с указателем на базовый класс будет неопределённое поведение. То, что вызывается деструктор базового класса — лишь один из вариантов проявления неопределённого поведения.

    Есть альтернативное решение, касающееся деструкторов базовых классов — объявить их защищёнными невиртуальными, если базовый класс или интерфейс не предназначен для полиморфного удаления

    1. Леонид К.:

      Тогда на этапе компиляции будет ошибка:
      1>error C2248: 'Parent::~Parent': cannot access protected member declared in class 'Parent'

      Т.е. это защита от неправильного использования указателя?

      Нужно явно вызывать

  4. Just a guy from Dagestan:

    Классный сайт! Спасибо, что объясняете всё понятно и бесплатно!

    1. Avatar photo Юрий:

      Пожалуйста 🙂

Добавить комментарий для Константин Отменить ответ

Ваш E-mail не будет опубликован. Обязательные поля помечены *