Подтвердить что ты не робот

Когда должен быть ваш деструктор виртуальным?

Возможный дубликат:
Когда использовать виртуальные деструкторы?

Когда должен быть ваш деструктор объекта С++ virtual?

4b9b3361

Ответ 1

  • Вам нужен виртуальный деструктор, когда на по меньшей мере один из методов класса виртуальная.

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

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

class A
{
   virtual void f() {}
   ~A() {}
}

class B : public A
{
   void f() {}
   ~B() {}
}

A * thing = new B();
thing->f(); // calls B f()
delete thing; // calls ~A(), not what you wanted, you wanted ~B()

имеющий ~ A() виртуальный оборот полиморфизма

virtual ~A() {}

Итак, когда вы сейчас звоните

delete thing;

~ B() будет вызываться.

Вы объявляете виртуальные деструкторы при разработке класса в качестве интерфейса, например. вы ожидаете, что он будет расширен или реализован. Хорошей практикой в ​​этом случае является наличие класса интерфейса (в смысле интерфейсов Java) с виртуальными методами и виртуальным деструктором, а затем конкретные классы реализации.

Вы можете видеть, что классы STL не имеют виртуальных деструкторов, поэтому они не должны расширяться (например, std::vector, std::string...). Если вы расширяете std::vector и вы вызываете деструктор в базовом классе с помощью указателя или ссылки, вы определенно не будете называть свой деструктор специализированного класса, что может привести к утечке памяти.

Ответ 2

Из Часто задаваемые вопросы по стилю и технике Stroustrup С++:

Итак, когда я должен объявить деструктор виртуальная? Всякий раз, когда класс имеет не менее одной виртуальной функции. имеющий виртуальные функции показывают, что класс должен действовать как интерфейс к производным классам, и когда это так, объектом производного класса может быть уничтожен через указатель на основа.

Много дополнительной информации о когда ваш деструктор должен быть виртуальным в FAQ по С++. (спасибо Stobor)

Что такое виртуальный член? Из Часто задаваемые вопросы по С++:

[20.1] Что такое "виртуальная функция-член"?

С точки зрения ОО, это единственная самая важная особенность С++: [6.9], [6.10].

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

Производный класс может либо полностью заменить ( "переопределить" ) базовый класс функция-член или производный класс может частично заменить ( "увеличить" ) функция базового класса. Последний осуществляется путем получения функция члена класса вызывает базовую функция члена класса, если требуется.

Ответ 3

Недавно я пришел к выводу, что полностью правильный ответ таков:

Руководство № 4: деструктор базового класса должны быть либо публичными, либо виртуальными, или защищенный и не виртуальный.

И, конечно, Herb Sutter дает обоснование своему требованию. Обратите внимание, что он выходит за рамки обычных ответов "когда кто-то удаляет объект производного класса с помощью указателя базового класса" и "делает ваш деструктор виртуальным, если ваш класс имеет какие-либо виртуальные функции".

Ответ 4

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

Я использую подход, который, если я собираюсь извлечь из класса AT ALL, тогда он должен иметь виртуальный деструктор. В коде, который я пишу, нет случаев, когда последствия производительности виртуального деструктора влияют на производительность, и даже если это действительно не нужно сегодня, оно может понадобиться в будущем, когда класс будет изменен.

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

Это просто еще одно эмпирическое правило, но это не позволяет вам совершать более поздние ошибки.

Ответ 5

Всегда.

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

Ответ 6

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

В общем, методы могут быть определены виртуальными в базовом классе, это позволит производным классам переопределять виртуальные методы, реализуя их собственную производную конкретную реализацию. Я считаю, что это наиболее ясно продемонстрировано на простом примере. Скажем, у нас есть базовый класс "Форма", теперь для всех производных классов может потребоваться способность рисовать. Объект "Shape" не будет знать, как рисовать классы, полученные из него, поэтому в классе "Shape" мы определяем функцию виртуального рисования. т.е. (virtual void draw();). Теперь в каждом базовом классе мы можем переопределить эту функцию, реализуя конкретный код чертежа (т.е. Квадрат рисуется иначе, чем круг).