Виртуальный деструктор при использовании апкастинга - PullRequest
3 голосов
/ 13 мая 2011

Все говорят, что деструктор должен быть виртуальным, когда хотя бы один из методов класса является виртуальным.
Мои вопросы, не правильно ли говорить, что деструктор должен быть виртуальным при использовании апкастинга?

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.И да, я знаю, что бессмысленно использовать расширение, если у меня нет виртуальных функций.

Спасибо.

Ответы [ 5 ]

13 голосов
/ 13 мая 2011

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

6 голосов
/ 13 мая 2011

деструктор должен быть виртуальным, если хотя бы один из методов класса является виртуальным

Это практическое правило, которое вытекает из того факта, что когда вы используете виртуальные функции, вы используете полиморфизм во время выполнения и с большей вероятностью сталкиваетесь с ситуациями, когда вам нужно уничтожить класс, который может быть производного типа, когда все вы have - указатель на подобъект базового класса.

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

Херб Саттер придерживался принципа, согласно которому деструкторы базового класса (т.е. деструкторы для классов, предназначенных для наследования) должны быть либо public и virtual или protected и не- virtual. Это дает возможность того, что базовый класс не является точкой в ​​иерархии наследования, которая используется для удаления производных объектов, и вы хотите, чтобы это не произошло непреднамеренно.

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

1 голос
/ 13 мая 2011

Деструктор должен быть сделан virtual, если вы делаете что-то полезное (освобождение памяти и т. Д.) В деструкторе производного класса.

Кстати, желательно (не обязательно)) иметь виртуальный деструктор, когда class содержит метод virtual.

1 голос
/ 13 мая 2011

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

0 голосов
/ 13 мая 2011

Это неверно:

shared_ptr<A> ptr = make_shared<B>();

выполняет приведение и удаляет B правильно.Просто следуйте ответу Нила Баттерворта.

...