← Назад к вопросам
Когда следует объявлять деструктор виртуальным?
1.8 Middle🔥 191 комментариев
#ООП и проектирование#Язык C++
Комментарии (1)
🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Когда следует объявлять деструктор виртуальным?
Краткий ответ
Деструктор должен быть виртуальным в базовом классе, если он используется для наследования и объекты удаляются через указатель на базовый класс.
Почему это критично?
Без виртуального деструктора происходит утечка памяти. Удаляя объект производного класса через указатель на базовый класс без virtual, вызывается только деструктор базового класса, а деструктор производного класса не вызывается.
Пример проблемы
class Base {
public:
~Base() { cout << "Base деструктор\\n"; }
};
class Derived : public Base {
public:
int* data;
Derived() : data(new int[1000]) {}
~Derived() {
cout << "Derived деструктор\\n";
delete[] data; // НЕ вызовется!
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // ПРОБЛЕМА! Только ~Base()
}
Вывод:
Base деструктор
// Derived деструктор НЕ вызван, утечка!
Правильное решение
class Base {
public:
virtual ~Base() { cout << "Base деструктор\\n"; }
};
class Derived : public Base {
public:
int* data;
Derived() : data(new int[1000]) {}
virtual ~Derived() {
cout << "Derived деструктор\\n";
delete[] data;
}
};
int main() {
Base* ptr = new Derived();
delete ptr; // Вызовется ~Derived(), потом ~Base()
}
Вывод:
Derived деструктор
Base деструктор
Правила
1. Базовый класс — деструктор ВСЕГДА virtual
class Shape {
public:
virtual ~Shape() {}
};
class Circle : public Shape {};
2. Если НЕ наследуется — может быть невиртуальным
class FinalClass {
public:
~FinalClass() {} // Невиртуальный — OK
};
class StrictFinal final {
public:
~StrictFinal() {}
};
3. Производные классы — virtual для ясности
class Base {
public:
virtual ~Base() = default;
};
class Derived : public Base {
public:
virtual ~Derived() = default;
};
C++ стиль: = default
class Base {
public:
virtual ~Base() = default;
};
Когда виртуальный деструктор НЕ нужен
- Листовые классы (не наследуются)
- Final классы
- Классы, явно запрещающие наследование
- std::string, std::vector, std::map (не для наследования)
Критически важное замечание
НИКОГДА удалять объект производного класса через базовый указатель без virtual деструктора — это гарантированная утечка памяти и неопределённое поведение.