3

Как работает виртуальный деструктор при наследовании мне известно. Мне интересен механизм работы.

Указатель на виртуальный деструктор также хранится в vtable? Если да, то порядок такой же как и у остальных виртуальных методов класса в таблице внутри vtable? или оно устроено как-то по-другому, есть отличие от виртуальных методов в способе хранения?

И как обстоит дело с обычным деструктором, он хранится как обычный метод?

Kromster
  • 13,809
Umed
  • 2,278
  • 1
    Важные детали очень просты: если у вас невиртуальный деструктор, вызов delete по указателю на базовый класс ведёт к undefined behaviour. Всё остальное — детали имплементации каждого конкретного компилятора. – VladD May 30 '16 at 16:15
  • 1
    Наличие таблицы виртуальных методов не гарантировано стандартом. Поэтому если уж говорить о таблице виртуальных методов, то нужно говорит о конкретном компиляторе/компиляторах. Механизм точно так же не оговаривается стандартом, каждый компилятор имеет право на свою имплементацию. – VladD May 30 '16 at 18:32

2 Answers2

5

Разница в том, что если у вас планируется хоть какое-то наследование, то скорее всего будет создан объект потомка, на который будет указывать указатель на базовый класс.

Base * b = new Derived;
...
delete b;

И вот тут, если деструктор не виртуальный, будет вызван деструктор ~Base(), что очень плохо... А если виртуальный - будет вызван деструктор ~Derived(), что и требуется...

Так что главное правило - планируете наследование - делайте деструктор виртуальным!

Harry
  • 221,325
  • 1
    Если деструктор базового класса не виртуальный, то после delete b будет вызван ТОЛЬКО деструктор базового класса, иначе будет вызван деструктор производного, а потом и базового, что и нужно. – Александр May 30 '16 at 11:36
  • Если полиморфного удаления не планируется, виртуальный деструктор не является обязательным несмотря на наличие иерархии классов. – αλεχολυτ May 30 '16 at 11:46
  • @Александр Гм, а я что написал?.. – Harry May 30 '16 at 11:59
  • 2
    @alexolut Знать все заранее - нереально. В какой-то момент программа будет переделана, и начнутся неприятности. Конечно, можно вообще наследование и т.п. вещи реализовать на чистом C, если быть достаточно аккуратным... но зачем? :) Так и тут - лучше обезопасить себя заранее... – Harry May 30 '16 at 12:01
  • @Harry по Вашей формулировке, можно подумать, что с виртуальным деструктором будет вызван только ~Derived() – Александр May 30 '16 at 12:04
  • 1
    @Александр А разве деструктор производного класса не вызывает деструктор базового? Это же азы... – Harry May 30 '16 at 12:32
  • @Harry на мой взгляд, если человек спрашивает про виртуальный деструктор, то может быть не знаком с такими "азами". – Александр May 30 '16 at 12:33
  • @Александр ну, разве что... – Harry May 30 '16 at 12:34
  • @Harry, если ещё не читали Герба: http://www.gotw.ca/publications/mill18.htm (Guideline #4) – αλεχολυτ May 30 '16 at 13:16
  • @alexolut Это то же, что он писал в "Стандартах программирования на C++". – Harry May 30 '16 at 13:25
3

Деструктор в интересуемой Вами части ничем не будет отличаться от обычной функции-члена. Если Вы используете объект производного класса через указатель на базовый класс в процессе его удаления через delete, то деструктор базового класса должен быть виртуальным. Вот и всё.

αλεχολυτ
  • 28,987
  • 13
  • 60
  • 119
  • Cпасибо за ответ, Вы меня поняли чуть лучше остальных, но хотелось бы немножко подробней, я обновил описание вопроса. – Umed May 30 '16 at 18:24