Как / когда я использую виртуальный деструктор? - PullRequest
2 голосов
/ 04 декабря 2010

В настоящее время я пишу программу со следующей полиморфной иерархией: Base: Multinumber.Производные: Пары, Комплекс, Рациональный.Multinumber - это виртуальный класс, который никогда не создается.

В ходе моей программы я часто динамически управляю базовыми классами, поэтому мне нужен деструктор.У меня такой вопрос: как сделать виртуальный деструктор?В моем файле Multinumber.h сейчас у меня есть это:

  virtual ~Multinumber();

В моем Multinumber.cpp:

Multinumber::~Multinumber()
{
}

И во всех моих производных классах у меня есть это:

Rational::~Rational()
{
}

У меня ничего нет ни в одном из моих производных .h файлов.К сожалению, это не компилируется.Скорее я получаю эту ошибку:

Complex.cpp|75|error: definition of implicitly-declared 'virtual Complex::~Complex()'

Что не так с моим синтаксисом?Спасибо за любую помощь, вы можете дать мне.

Ответы [ 5 ]

4 голосов
/ 04 декабря 2010

Достаточно просто объявить деструктор virtual в базе и дать ему пустое определение. Для других классов вам вообще ничего не нужно делать, если только этим деструкторам не нужно работать.

Смысл объявления virtual в базовом классе состоит в том, чтобы гарантировать, что деструктор может быть вызван полиморфно (так, чтобы Base* d = new Derived(); delete d; работал правильно, вызывая дериватор Derived вместо базового деструктора). Затем вам нужно определить этот деструктор (даже если он не работает), потому что вы его объявили.

Однако для всех производных классов, если вы ничего не указали, для них генерируется деструктор по умолчанию «вызов деструкторов для членов и баз», и все работает так, как вам нужно. Если, опять же, вам не нужно делать что-либо еще, чтобы должным образом уничтожить объект.

Как отметил Dark Falcon, вам нужно объявление в базе для каждого определяемого вами члена, включая деструкторы. Так что если вы пишете Complex :: ~ Complex, тогда он должен быть объявлен в определении класса Complex, даже если вы наследуете от класса, который объявляет и определяет деструктор. (Деструкторы, как и конструкторы, на самом деле не наследуются; поведение по умолчанию «рекурсивный вызов для членов и баз» на самом деле не одно и то же. Эти функции особые, поскольку они управляют временем жизни объекта, а не его использованием. ) * +1010 *

3 голосов
/ 04 декабря 2010

Внутри класса Complex вам также нужно иметь объявление для деструктора:

~Complex();

Обратите внимание, что виртуальный здесь не является обязательным. Деструктор будет виртуальным, потому что деструктор базы является виртуальным.

2 голосов
/ 06 июля 2011

Когда объявлять виртуальный деструктор?

Я рекомендую вам следовать этому алгоритму, чтобы решить, следует ли объявлять виртуальный деструктор.

Предназначен ли ваш класс дляиспользуется в качестве базового класса?

  • Нет: объявлять не виртуальный деструктор (избегает использования v-указателя на каждый объект класса) и помните, что не следует выводить из конкретных классов.
  • Да: переходите к следующему вопросу.

Является ли ваш базовый класс абстрактным?(то есть какие-либо виртуальные чистые методы?)

  • Нет: попытайтесь сделать свой базовый класс абстрактным, изменив иерархию [1] (т.е. не позволяйте создавать экземпляр базового класса).
  • Да: переходите к следующему вопросу.

Хотите разрешить полиморфное удаление через базовый указатель?

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

Ссылки:

[1]: С. Мейерс.Более эффективный C ++, пункт 33 (Addison-Wesley, 1996).

[2]: «Виртуальность» http://www.gotw.ca/publications/mill18.htm

0 голосов
/ 12 июня 2015

Вопрос: когда не объявлять деструктор виртуальным?Нет недостатков в объявлении виртуального деструктора.

0 голосов
/ 06 июля 2011

Что не так с моим синтаксисом?

Следующее:

И во всех моих производных классах я имею это:

Rational :: ~ Rational () {}

Нет, нет.Вы не сделали это для Complex.

...