C ++ и виртуальные деструкторы - PullRequest
2 голосов
/ 25 ноября 2011

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

Несколько программистов позже - кто-то добавляет в мой служебный класс, наследуя его. Теперь, если где-нибудь в коде мой новый класс в new'd и удален, правильный dtor не будет вызываться, так как базовый класс dtor не был сделан виртуальным (см. Пример кода).

Кроме возврата назад и изменения базового класса - какие решения существуют в этом случае?

#include <iostream>
using namespace std;

class utility {
  int i, j;

  public:
    utility () { cout << "utility ctor\n";};
   ~utility () { cout << "utility dtor\n";};
    void dosomething () { cout << "haha\n";};
};

class addtoutility: public utility  {
  char *ch;

  public:
   addtoutility () { ch= new char(); cout << "added ctor\n";};
  ~addtoutility () { delete ch; cout << "added dtor\n";};
   void andnowaddsomefunctionality () {};
};

int main () {
  utility *u  = new addtoutility();
  //lots of interesthing code
  delete u;
}

Ответы [ 3 ]

6 голосов
/ 25 ноября 2011

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

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

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

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

3 голосов
/ 25 ноября 2011
  • Удалить через указатель правильного типа. Поскольку ни один из других методов не является виртуальным, на самом деле нет смысла рассматривать его полиморфно.

Работает:

addtoutility *u  = new addtoutility();

delete u;
  • Сделай это виртуальным. Если вы беспокоитесь о накладных расходах, то, вероятно, они незначительны.
  • Использовать статическое наследование с использованием CRTP. Единственная проблема заключается в том, что это может занять больше памяти, чем vtable.
0 голосов
/ 25 ноября 2011

Если вы вообще не можете изменить код базового класса, вы можете добавить функцию к производному классу, например Destroy (). Немного раздражает, но мы делаем это постоянно, если вы думаете о таких объектах Win32, как Brush.

...