Last Updated: January 3, 2026
When dealing with inheritance, especially in polymorphic scenarios, the destructor of a base class must be virtual to ensure that derived class destructors are called correctly.
This chapter will explore why virtual destructors are necessary, how to implement them, and the implications of their use in real-world applications.
When a program creates an object of a derived class and stores it in a pointer to a base class, the base class pointer can only call the base class's methods, unless those methods are declared as virtual. This principle applies to destructors as well.
If a base class destructor is not virtual, deleting an object of a derived class through a base class pointer leads to undefined behavior. This occurs because the derived class's destructor will not be invoked, potentially resulting in resource leaks or incomplete cleanup.
To illustrate this, consider the following code snippet:
In this example, when deleteBase tries to delete b, it only calls the Base destructor. As a result, the Derived destructor is never executed, leading to potential memory leaks.
To avoid the pitfalls mentioned, you should declare the destructor of the base class as virtual. This ensures that when you delete an object of a derived class through a base class pointer, the correct destructor is invoked. Here’s how to modify the previous example:
In this corrected version, when deleteBase is called, it invokes both the Derived and Base destructors in the correct order, ensuring that resources are properly released.
Virtual destructors are essential in scenarios where you are working with dynamic polymorphism. Here are some common use cases:
If your classes manage resources (like memory, file handles, or database connections), having a virtual destructor ensures proper cleanup:
In this example, using a virtual destructor in the Resource class guarantees that all derived resources are cleaned up correctly.
When designing interfaces using pure virtual functions, especially when these interfaces are expected to be deleted through base class pointers, virtual destructors become crucial:
Here, Drawable serves as an interface, and by providing a virtual destructor, you ensure that any derived class like Circle can be destructed properly.
While virtual destructors are generally straightforward, there are some nuances to be aware of:
Always declare the destructor of a base class as virtual, even if that class does not have any dynamically allocated resources. This practice avoids potential issues in the future if the class is extended.
One downside of virtual destructors is a slight performance overhead due to the virtual table (vtable) lookup. In most applications, this overhead is negligible, but in performance-critical code, you should profile to ensure it’s not a bottleneck.
When you declare a destructor as virtual, it's also important to know that if you don't define a destructor in the base class, the compiler provides a default one. This default destructor will still call the destructors of derived classes, as long as they are virtual.
Remember that while destructors can be virtual, constructors cannot. If a derived class needs specific initialization, you must call the base class constructor explicitly, as shown in the earlier examples.