Деструктор по умолчанию в подклассах базового класса с виртуальным деструктором
У меня есть базовый класс A
с виртуальным деструктором. A
имеет потомков B
а также C
которые используют деструктор по умолчанию. Безопасно ли удалять объект C
через указатель на A
?
В частности, рассмотрим этот пример кода:
class A {
public:
A(){};
virtual ~A() {/* code here */};
};
class B: public A {
B() {/* code....*/};
/* NO DESTRUCTOR SPECIFIED */
};
class C: public B {/*same as above, no destructor */};
class D: public B {/* same as above, no destructor*/}
Код для запуска выглядит примерно так:
A* getAPointer(void); /* a function returning a C or a D*/
A* aptr=getAPointer();
/* aptr is declared as A*, but points to either an object of class C
or class D*/
delete aptr;
Это delete aptr
безопасный? Делает ли это правильно: если aptr
указывает на объект класса C
, aptr
первые звонки C
деструктор, то B
деструктор, и наконец A
деструктор?
3 ответа
Безопасно ли удалять объект C через указатель на A?
Да, это абсолютно безопасно, так как все деструкторы в классах B
, C
а также D
будет неявно виртуальным.
От:
15.4 Деструкторы [class.dtor]
10 Деструктор может быть объявлен виртуальным (13.3) или чисто виртуальным (13.4); если какие-либо объекты этого класса или любого производного класса созданы в программе, деструктор должен быть определен. Если у класса есть базовый класс с виртуальным деструктором, его деструктор (объявленный пользователем или неявно) является виртуальным.
Как A
имеет виртуальный деструктор, то B
, а также C
, D
соответственно есть виртуальные деструкторы и:
delete aptr;
работает правильно.
Да, это безопасно. Добавление virtual
для деструкторов ваших производных классов является излишним.
Рассмотрим, как работает механизм. когда delete
используется, среда выполнения должна знать, с какого деструктора должна начинаться цепочка уничтожения. Если статический тип delete
операнд имеет virtual
деструктор, тогда и этого достаточно для того, чтобы среда выполнения знала, что он должен принять дополнительные меры, и проверить динамический тип.
В вашем случае он обнаруживает, что динамический тип C
, так C::~C
называется. C::~C
автоматически приводит к B::~B
и это автоматически приводит к A::~A
,
Требование к C
х (или B
х) деструктор virtual
было бы бессмысленно. В конце концов, среда выполнения должна выяснить динамические C
в любом случае, если A::~A
является virtual
, На этом этапе все равно, C::~C
является virtual
или нет. Какая разница это будет иметь?
Безопасно ли удалять объект
C
через указатель наA
?
Да. поскольку A
деструктор виртуален, C
деструктор будет называться. Это просто из-за того, как работает динамическая диспетчеризация.