🏛️Go deeper — read the bookObject-Oriented Programming in C++— runnable code & full walkthrough →

oops · high

Virtual Destructor

When you delete an object through a pointer to a base class, the compiler chooses the destructor based on the destructor's own dispatch kind. If the base destructor is non-virtual, the call is static and only ~Base runs: the derived class's destructor is skipped, any resources it owns leak, and the standard declares the whole thing undefined behavior. Declaring the base destructor virtual makes the class polymorphic (each object gains a vptr); delete p then dispatches through the vtable to the most-derived destructor, running ~Derived first and then ~Base bottom-up. Rule of thumb: any class intended to be deleted through a base pointer needs a virtual destructor — or a protected, non-virtual one to forbid such deletion at compile time.

🔑 Key line

Deleting a derived object through a base pointer requires a virtual destructor: with a non-virtual base destructor only ~Base runs (the derived part leaks and it is undefined behavior), while a virtual one dispatches through the vtable to run ~Derived then ~Base.

The code

struct Base {
~Base() {} // NON-virtual destructor (the bug)
};
struct Derived : Base {
int* data = new int[64]; // Derived owns a heap resource
~Derived() {
delete[] data;
}
};
Base* p = new Derived(); // static type Base*, dynamic type Derived
delete p; // non-virtual ~Base: only ~Base runs -> ~Derived skipped (UB + leak)
// FIX: make the base destructor virtual
struct Base {
virtual ~Base() {}
}; // delete p now runs ~Derived, then ~Base

What this lesson walks through

  1. 01A base pointer to a resource-owning derived
  2. 02Non-virtual dtor: ~Derived is skipped
  3. 03The fix: make ~Base virtual
  4. 04Virtual dispatch finds ~Derived first
  5. 05Then ~Base runs — bottom-up teardown
  6. 06When you need a virtual destructor
  7. 07The rule in one breath

p has static type Base* but points to a Derived that owns a heap buffer (data). When we delete p, the compiler decides which destructor to call based on the type of the destructor — not on what p actually points to.

See it animated — step by step, at your own pace

Unlock the full interactive walkthrough of Virtual Destructor and 100+ animated C++ interview lessons.

← Previous
Overloading vs Overriding vs Hiding
Next →
Virtual Calls in Ctors & Dtors