Introduction

In C++, a virtual destructor is used to ensure proper destruction of objects when they are deleted through a pointer to the base class. This concept is important when dealing with polymorphism and inheritance to avoid memory leaks and undefined behavior.

In C++ , the constructor cannot be virtual, because when a constructor of class is executed there is no virtual table in the memory, means no virtual pointer defined yet. So, the constructor should always be non-virtual. But virtual destructor is possible.

Defined Virtual Destructor

When a class is derived from another class (base class) and objects of the derived class are created, it is possible to use pointers of the base class to point to objects of the derived class. In this situation, if the base class destructor is not virtual and an object is deleted through a pointer of the base class, only the base class destructor will be called. This can lead to incomplete destruction and potential memory leaks for the derived class resources.

To address this issue, C++ introduces the concept of a virtual destructor. By making the base class destructor virtual, the compiler ensures that the most derived class’s destructor is called when an object is deleted through a pointer to the base class. This allows all the destructors in the inheritance chain to be called, ensuring that resources allocated in each class are properly released.

The syntax to declare a virtual destructor in C++ is as follows:

class Base {
public:
    virtual ~Base() {
        // Base class destructor code
    }
};

class Derived : public Base {
public:
    ~Derived() override {
        // Derived class destructor code
    }
};

Key points to note about the virtual destructor

Key points to note about virtual destructors:

  1. Virtual destructors should be declared in the base class. It is not necessary to declare them as virtual in the derived classes unless you intend to override them in the derived class .
  2. The virtual keyword is not needed in the derived class when overriding the base class destructor. However, using the override keyword explicitly indicates that the function is intended to override a virtual function, making the code more readable.
  3. When a destructor is declared virtual, the C++ runtime uses dynamic binding to call the appropriate destructor, depending on the actual object type pointed to by the base class pointer.
  4. If a class does not allocate any resources dynamically (e.g., using new), it might not require a virtual destructor. However, it is generally good practice to provide a virtual destructor in base classes, especially if you anticipate future derived classes that may require dynamic memory management.
  5. Note that virtual destructors are not needed for objects created on the stack (automatic storage duration) since they are automatically destructed in the reverse order of construction. Virtual destructors are mainly used for objects created on the heap (dynamic storage duration) using new.

Example of Virtual Destructor

#include <iostream>

class Base {
public:
    Base() {
        std::cout << "Base constructor called." << std::endl;
    }

    // Virtual destructor
    virtual ~Base() {
        std::cout << "Base destructor called." << std::endl;
    }

    // A virtual function
    virtual void doSomething() {
        std::cout << "Base doSomething() called." << std::endl;
    }
};

class Derived : public Base {
public:
    Derived() {
        std::cout << "Derived constructor called." << std::endl;
    }

    // Destructor (implicitly virtual, due to the virtual destructor in the Base class)
    ~Derived() {
        std::cout << "Derived destructor called." << std::endl;
    }

    // Override the virtual function
    void doSomething() override {
        std::cout << "Derived doSomething() called." << std::endl;
    }
};

int main() {
    // Create a derived object and access it through a base class pointer
    Base* basePtr = new Derived();

    // Call the virtual function
    basePtr->doSomething();

    // Delete the object through the base class pointer
    delete basePtr;

    return 0;
}

output

Base constructor called.
Derived constructor called.
Derived doSomething() called.
Derived destructor called.
Base destructor called.

Conclusion

To summarize, a virtual destructor is essential in C++ when working with inheritance and polymorphism to ensure that the correct destructors are called, preventing resource leaks and undefined behavior. Always use virtual destructors when you have a base class with virtual functions to ensure proper cleanup of resources when deleting objects through base class pointers.


more related content on Object Oriented Programming