When to use virtual destructors in C++?

To ensure safe and proper cleanup of derived class objects when deleting them through a base class pointer, use a virtual destructor in the base class under the following circumstances:

When to Use Virtual Destructors

  1. Polymorphic Base Classes
    If your class is intended to be inherited from and you will delete objects of derived classes via a base class pointer, the base class must have a virtual destructor.
    Example:
   class Base {
   public:
       virtual ~Base() {} // Virtual destructor
   };

   class Derived : public Base {
   public:
       ~Derived() { /* Cleanup resources */ }
   };

   Base* ptr = new Derived();
   delete ptr; // Correctly calls Derived's destructor ✅
  1. Classes with Virtual Functions
    If a class has any virtual functions, its destructor should also be virtual.
    Rationale: Virtual functions imply the class is designed for polymorphism, so cleanup must work correctly.
  2. Abstract Base Classes (ABCs)
    Even if an abstract class has no other virtual functions, its destructor should be virtual:
   class Shape {
   public:
       virtual void draw() = 0;
       virtual ~Shape() {} // Virtual destructor
   };

When NOT to Use Virtual Destructors

  • Non-Polymorphic Classes
    If a class is not intended to be inherited from (e.g., utility classes), avoid the overhead of a virtual destructor.
  • Final Classes (C++11+)
    If a class is marked final, no virtual destructor is needed:
  class NonInheritable final { /* ... */ };

Key Consequences of Missing Virtual Destructors

class Base { /* No virtual destructor */ };
class Derived : public Base { /* ... */ };

Base* ptr = new Derived();
delete ptr; // Undefined behavior: Derived's destructor is NOT called ❌

Best Practices

  • Rule of Three/Five: If you define a custom destructor, follow the Rule of Three/Five (implement copy/move constructors/operators).
  • Avoid Public Non-Virtual Destructors in Base Classes: This risks resource leaks.

By using virtual destructors in base classes, you ensure proper cleanup and prevent undefined behavior in polymorphic hierarchies.

Leave a Reply

Your email address will not be published. Required fields are marked *