Заставить виртуальных деструкторов? C++

Я не видел ответа на этот вопрос в C++ Faq lite:

Как определить базовый класс, чтобы каждый наследующий его класс требовал определения деструктора?

Я пытался запустить эту программу

struct VDtor { virtual ~VDtor()=0;  };
struct Test:VDtor { virtual ~Test(){}  };
int main() { delete new Test; return 0; }

http://codepad.org/wFcE71w3 с ошибкой

In function `Test::~Test()':
t.cpp:(.gnu.linkonce.t._ZN4TestD0Ev+0x1e): undefined reference to `VDtor::~VDtor()'
In function `Test::~Test()':
t.cpp:(.gnu.linkonce.t._ZN4TestD1Ev+0x1e): undefined reference to `VDtor::~VDtor()'

Так возможно ли это?

4 ответа

Решение

В некотором смысле это "возможно" (если ваша цель состояла в том, чтобы производный класс остался абстрактным в противном случае). Но он не даст желаемого результата: потому что компилятор сам неявно создаст деструктор, если программист этого не сделал.

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

(edit: Как отмечалось в заметках @chubsdad, ошибка в вашем конкретном коде заключается в том, что вам нужно определить явно объявленный деструктор базового класса).


Редактировать: просто для удовольствия, есть ситуации, которые требуют явно объявленного конструктора. Рассмотрим следующее

struct Viral {
  struct Dose { };
protected:
  ~Viral() throw (Dose) { }
};

struct Base {
  virtual ~Base() throw() { }
};

struct Derived : Base, Viral { };

Этот код не будет компилироваться, потому что неявно объявленный ~Derived будет иметь спецификацию исключения throw (Dose) который слабее чем ~Base имеет - поэтому он нарушает требование, чтобы переопределители не имели более слабой спецификации исключений. Вам нужно будет явно объявить деструктор соответствующим образом

struct Derived : Base, Viral { ~Derived() throw() { } };

Но это не совсем решение вашей проблемы, потому что производные классы должны "сотрудничать" в Viral или положить его в качестве нестатического члена данных. Это тоже очень некрасиво:)


Изменить: следующее, кажется, соответствует стандартному способ сделать это

struct Viral {
  struct Dose { };
protected:
  ~Viral() throw (Dose) { }
};

struct Base : virtual Viral {
  virtual ~Base() throw() { }
};

Clang и GCC ( начиная с v4.6) отклоняют любой производный класс Base который имеет неявно объявленный деструктор, потому что у него есть несовместимая спецификация исключений (любой производный класс должен вызывать ~Viral прямо, а не косвенно, позвонив ~Base Стандарт говорит). Comeau принимает это, но я сильно подозреваю, что это не соответствует этому.

struct VDtor { virtual ~VDtor()=0;  };
VDtor::~VDtor () { } // <== Implementation.
struct Test:VDtor { ~Test(){}  };
int main() { delete new Test; return 0; }

Чтобы исправить ошибку, вы должны реализовать VDtor::~VDtor(), как описано выше.

В каждом классе есть деструктор. Объявление виртуального деструктора в базе гарантирует, что у детей будут виртуальные деструкторы. Это не означает, что кодировщику нужно будет явно объявить деструктор - это было бы не очень хорошо, во всяком случае. Все это означает, что, если деструктор объявлен, он будет виртуальным.

Когда Test уничтожается, он вызывает деструктор базового класса, которого не существует. Вы должны просто объявить его пустым, если у вас нет необходимой логики уничтожения.

Другие вопросы по тегам