2010-09-13 1 views
16

Я не видел ответа на это в C++ Faq lite:Принудительные виртуальные деструкторы? C++

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

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

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()' 

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

+17

+1 для того, что, вероятно, самый компактный, но автономный примерный код, который я видел до сих пор. :-D – DevSolar

+1

Почему? Какой смысл заставлять пользователя писать больше кода? Если у вас есть очистка, сделайте это самостоятельно, не ставьте бремя на пользователя; если вы этого не сделаете, это бесполезно. Не могли бы вы привести пример ситуации, в которой это было бы действительно полезно? –

+0

@Matthieu M .: генерируемый код пропускает только void *, а потом создаются дочерние элементы, а потом потом случайные функции в случайном порядке, чтобы передать params/child родителям. Ужасный беспорядок. Каждая структура получит пустоту *, и я должен помнить, чтобы ее очистить. Возможно, auto_ptr решит его, но я не уверен в побочных эффектах, и половина классов, похоже, будет выполнена. – 2010-09-13 13:07:28

ответ

17

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

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

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


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

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

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

struct Derived : Base, Viral { }; 

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

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

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


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

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

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

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

+1

+1: Я полностью забыл о неявном деструкторе, отвечая на это. – Chubsdad

+0

Значит ли это, что нет? Невозможно заставить класс вывода определить dtor? – 2010-09-13 13:01:12

+1

@acid, я бы сказал, что невозможно заставить программиста явно определить деструктор в производном классе. Не могли бы вы показать, для чего вам это нужно? –

1

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

+1

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

+0

@Fred: Да, я должен был более ясно объяснить, что даже неявно объявленные деструкторы в дочерних классах всегда будут виртуальными. После виртуального, всегда виртуального. Спасибо, что указали на отсутствие ясности здесь. –

+0

Глядя на него снова, «если объявлен деструктор», я обнаружил проблему: dtor всегда * объявляется либо программистом, либо неявным компилятором. (Это кажется намного более ясным, чем мой предыдущий комментарий.) –

0

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

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

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

+0

Но это не делает вывод класса для реализации собственного деструктора. – 2010-09-13 15:31:47

+4

@ acidzombie24: Либо класс нуждается в непустом дторе, а затем ничего, что может сделать база, поможет или неявный и пустой dtor достаточно хорош, и тогда нет смысла четко указывать его, ИМХО. – wilx