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

Форсировать виртуальные деструкторы? С++

Я не видел ответа на это в С++ 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()'

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

4b9b3361

Ответ 1

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

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

(редактирование: как отмечено примечание @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, говорится в стандарте). Комо соглашается с этим, но я сильно подозреваю, что в этом отношении он не соответствует требованиям.

Ответ 2

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

Ответ 3

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

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

Ответ 4

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