Виртуальный деструктор при использовании апкастинга
Все говорят, что деструктор должен быть виртуальным, когда хотя бы один из методов класса является виртуальным.
Мои вопросы: не правильно ли говорить, что деструктор должен быть виртуальным при использовании апкастинга?
class A {
public:
~A(){
cout << "Destructor in A" << endl;
}
};
class B: public A
{
public:
~B(){
cout << "Destructor in B" << endl;
}
};
int main()
{
A* a = new B;
cout << "Exiting main" << endl;
delete a;
}
В этом коде нет никаких виртуальных функций, но если я не сделаю свой базовый деструктор виртуальным, он не будет вызывать деструктор B. И да, я знаю, что бессмысленно использовать ucpasting, если у меня нет виртуальных функций.
Спасибо.
5 ответов
деструктор должен быть виртуальным, если хотя бы один из методов класса является виртуальным
Это практическое правило, которое вытекает из того факта, что когда вы используете виртуальные функции, вы используете полиморфизм во время выполнения и с большей вероятностью сталкиваетесь с ситуациями, когда вам нужно уничтожить класс, который может быть производного типа, когда все, что у вас есть, это указатель на его подобъект базового класса.
Когда вы уничтожаете производный объект с помощью delete
по указателю на базовый класс необходим виртуальный деструктор в базовом классе, чтобы избежать неопределенного поведения. Это единственный раз, когда необходим виртуальный деструктор, и руководство призвано помочь избежать возникновения такой ситуации.
Херб Саттер отстаивал принцип, согласно которому деструкторы базового класса (т.е. деструкторы для классов, предназначенных для наследования) должны быть либо public
а также virtual
или же protected
и неvirtual
, Это дает возможность того, что базовый класс не является точкой в иерархии наследования, которая используется для удаления производных объектов, и вы хотите, чтобы это не произошло непреднамеренно.
Конечно, если у вас есть класс с чистыми значениями, который не является базовым классом, вы мало что можете сделать, чтобы в любом случае остановить людей, производных от него, и затем удалить производный класс с помощью указателя на базу.
Вам нужен виртуальный деструктор, если вы когда-либо удаляете производный объект через базовый указатель. Вот и все, в двух словах.
Деструктор должен быть сделан virtual
если вы делаете что-то полезное (освобождение памяти и т. д.) в деструкторе производного класса.
Кстати, желательно (не обязательно) иметь виртуальный деструктор, когда class
содержит virtual
метод.
Вы должны всегда объявлять виртуальный деструктор, когда один из методов класса является виртуальным, если вы удаляете указатель на производный класс, но тип указателя является базовым классом, тогда базовый класс должен иметь виртуальный деструктор в этом случае, или компилятор не 't (или не должен) знать, какой деструктор он должен вызывать (и это UB).
Это неверно:
shared_ptr<A> ptr = make_shared<B>();
делает приведение и удаляет B
правильно. Просто следуйте ответу @Neil Butterworth.