Достаточно просто объявить деструктор virtual
в базе и дать ему пустое определение. Для других классов вам вообще ничего не нужно делать, если только этим деструкторам не нужно работать.
Смысл объявления virtual
в базовом классе состоит в том, чтобы гарантировать, что деструктор может быть вызван полиморфно (так, чтобы Base* d = new Derived(); delete d;
работал правильно, вызывая дериватор Derived вместо базового деструктора). Затем вам нужно определить этот деструктор (даже если он не работает), потому что вы его объявили.
Однако для всех производных классов, если вы ничего не указали, для них генерируется деструктор по умолчанию «вызов деструкторов для членов и баз», и все работает так, как вам нужно. Если, опять же, вам не нужно делать что-либо еще, чтобы должным образом уничтожить объект.
Как отметил Dark Falcon, вам нужно объявление в базе для каждого определяемого вами члена, включая деструкторы. Так что если вы пишете Complex :: ~ Complex, тогда он должен быть объявлен в определении класса Complex, даже если вы наследуете от класса, который объявляет и определяет деструктор. (Деструкторы, как и конструкторы, на самом деле не наследуются; поведение по умолчанию «рекурсивный вызов для членов и баз» на самом деле не одно и то же. Эти функции особые, поскольку они управляют временем жизни объекта, а не его использованием. ) * +1010 *