Virtual Destructor In C++ - C++ Programming Tutorial
C++ Course / Polymorphism / Virtual Destructor In C++

Virtual Destructor In C++

BLUF: Mastering Virtual Destructor In C++ is a critical step in becoming a proficient C++ developer. This lesson provides a deep dive into the syntax, performance considerations, and real-world applications of this concept.
Key Performance Insight: Virtual Destructor In C++

C++ is renowned for its efficiency. Learn how Virtual Destructor In C++ enables low-level control and high-performance computing in the tutorial below.

In C++, a virtual destructor is employed to deallocate the memory assigned by the derived class object when deleting instances of the derived class through a base class pointer object. The virtual keyword in the base or parent class destructor guarantees that both the base class and the derived class destructor will be invoked during runtime. However, the derived class destructor is called first, followed by the base class destructor, to release the memory occupied by both destructors.

Syntax

It has the following syntax:

Example

class Base {

public:

    virtual ~Base(); // Virtual destructor

};

Simple Virtual Destructor Example

Let's consider a scenario to showcase the concept of a virtual destructor in the C++ programming language.

Example

Example

#include <iostream>

using namespace std;  //using standard namespace

class Base {

public:   //Access Modifier

    virtual ~Base() {

        cout << "Base Destructor\n";

    }

};

class Derived : public Base {   //Derived Class

public:

    ~Derived() {

        cout << "Derived Destructor\n";

    }

};

int main() {   //Main Function

    Base* ptr = new Derived();  // Base pointer to Derived object

    delete ptr;     // Delete via base pointer

    return 0;

}

Output:

Output

Derived Destructor

Base Destructor

Explanation

In this case, the ptr acts as a pointer to the base class pointing to an object of the Derived class. The base class includes a virtual destructor. Upon executing delete ptr within the main function, the destructor of the Derived class is invoked initially, succeeded by the destructor of the Base class. This sequence guarantees the appropriate cleanup of both the derived and base components of the object.

Why do we use virtual destructor in C++?

When an object within a class reaches the end of its scope or when the main function finishes execution, the program automatically invokes a destructor to release the memory allocated by the class' destructor function. If a pointer object of the base class is deleted that points to a derived class object, only the base class destructor is invoked because of early binding by the compiler. As a result, the derived class' destructor is not called, potentially causing memory leak problems in the application.

If the virtual keyword is employed along with the destructor tilde (~) sign in the base class, it ensures that the derived class' destructor is invoked initially. Subsequently, the base class' destructor is invoked to deallocate the memory held by both destructors in the inherited class.

How Virtual Destructors Work Internally

In C++, compilers create vtable entities when constructing classes with virtual functions and destructors. Each object of the class holds hidden vtable pointers within its layout.

C++ conducts runtime type checks by accessing the vtable to identify which destructors require execution when the destructor is marked as virtual.

Usage of Virtual Destructor

There are multiple purposes for utilizing a virtual destructor in C++. A few examples are:

1) Polymorphic Deletion via Base Pointer

A pointer to a base class seeks to delete an object of a derived class, resulting in the execution of only the base class destructor in the absence of a virtual destructor. Consequently, the derived class destructor fails to execute, leading to resource leaks.

C++ Polymorphic Deletion via Base Pointer

Let's consider an example to demonstrate polymorphic deletion using a base pointer in C++.

Example

Example

#include <iostream> 

using namespace std;  //using standard namespace

class Base {

public:

    ~Base() {

        cout << "Base Destructor\n";

    }

};

class Derived : public Base {

public:

    ~Derived() {

        cout << "Derived Destructor\n";

    }

};

int main() {  //Main Function

    Base* ptr = new Derived();

    delete ptr; // Undefined behavior

    return 0;

}

Output:

Output

Base Destructor

Explanation

In this instance, the parent class neglects to include a virtual destructor declaration. When the delete ptr command is invoked, it calls the Base destructor and bypasses the execution of any Derived destructor. Consequently, instances of the derived class would encounter memory leaks as they are unable to properly deallocate dynamic memory or release file handles.

2) Interface-like Base Class

In C++, utilizing a virtual destructor declaration in the base class enables the vtable to correctly manage destructor sequences during runtime.

Example

Let's consider an example to demonstrate the base class that resembles an interface in C++.

Example

Example

#include <iostream>

using namespace std;  //using standard namespace

class Base {

public:  //Access Modifier

    virtual ~Base() {

        cout << "Base Destructor\n";

    }

};

class Derived : public Base {   //Derived Class

public:

    ~Derived() {

        cout << "Derived Destructor\n";

    }

};

int main() {    //Main Function

    Base* ptr = new Derived();

    delete ptr; // Safe deletion

    return 0;

}

Output:

Output

Derived Destructor  

Base Destructor

Explanation

In this instance, both destructors are invoked in the proper sequence. Subsequently, the assurance of full object destruction is ensured.

3) Managing Dynamic Resources in Derived Classes

In C++, subclasses are responsible for managing resources such as memory or file handles. Without a virtual destructor in the superclass, these resources will not be properly deallocated when deleted in a polymorphic manner.

In this C++ example, we will demonstrate how to handle dynamic resources in subclasses.

Let's consider an instance to demonstrate the handling of dynamic resources in subclasses within C++.

Example

Example

#include <iostream>

using namespace std;   //using standard namespace

class Base {

public:

    virtual ~Base() {

        cout << "Base cleaned up\n";

    }

};

class Derived : public Base {

private:

    int* data;

public:

    Derived() {

        data = new int[5];

        cout << "Derived allocated memory\n";

    }

    ~Derived() {

        delete[] data;

        cout << "Derived released memory\n";

    }

};

int main() {   //Main Function

    Base* b = new Derived();

    delete b; // Proper cleanup

    return 0;

}

Output:

Output

Derived allocated memory  

Derived released memory  

Base cleaned up

Explanation

In this instance, we avoid memory leaks by properly handling resources in subclasses.

C++ Example to display a Class Destructor without using a Virtual Destructor

Let's consider a program that demonstrates undefined behavior in a class destructor without employing a virtual destructor in C++.

Example

Example

#include<iostream>  

using namespace std;   //using standard namespace

class Base  

{                              

    public: //Access Modifier

    Base() // Constructor function.   

{  

    cout<< "\n Constructor Base class";  

}  

 ~Base() // Destructor function   

{  

    cout<< "\n Destructor Base class";  

}  

};  

class Derived: public Base  

{  

    public: 

    Derived() // Constructor function   

{  

    cout << "\n Constructor Derived class" ;  

}  

 ~Derived() // Destructor function   

{  

    cout << "\n Destructor Derived class" ; /* Destructor function is not called to release its space. */  

}         

};  

int main()    //Main Function

{  

    Base *bptr = new Derived; // Create a base class pointer object   

       delete bptr;  //delete pointer

}

Output:

Output

Constructor Base class

 Constructor Derived class

 Destructor Base class

Explanation

In this instance, we've utilized a Base* pointer to instantiate a Derived object. Additionally, a base class was employed. Subsequently, the program deallocates the memory occupied by the pointer object using the base class' destructor and the derived class's destructor. However, the base class pointer solely invokes the base class's destructor while omitting the derived class's destructor. Consequently, memory leakage occurs within the program.

C++ Example to display a Class Destructor using a Virtual Destructor

Let's consider a program that demonstrates the functionality of a class destructor by utilizing a virtual destructor in C++.

Example

Example

#include<iostream>  

using namespace std;   //using standard namespace

class Base  

{  

    public:  

    Base() // Constructor member function.    

{  

    cout << "\n Constructor Base class";  // It prints first.  

}  

 virtual ~Base() // Define the virtual destructor function  

{  

    cout << "\n Destructor Base class";

}  

};  

// Inheritance concept  

class Derived: public Base   

{  

    public:  

    Derived() // Constructor function.  

{  

    cout << "\n Constructor Derived class"; 

}  

 ~Derived() // Destructor function   

{  

    cout << "\n Destructor Derived class"; 

}         

};  

int main() //Main Function

{  

    Base *bptr = new Derived; // A pointer object references the Base class.  

    delete bptr; // Delete the pointer object.  

}

Output:

Output

Constructor Base class

 Constructor Derived class

 Destructor Derived class

 Destructor Base class

Explanation

In the preceding program, a virtual destructor has been employed within the base class to execute the destructor of the derived class prior to executing the base class' destructor. This process aids in releasing memory spaces and rectifying any memory leak problems within the program.

Conclusion

In summary, the incorporation of virtual destructors in C++ facilitates the appropriate disposal of objects within polymorphic class inheritance structures. By employing virtual destructors, the program can invoke both base and derived class destructors when deleting a base pointer. In cases where virtual destructors are absent, only the base destructor is invoked, posing a potential memory hazard.

C++ Virtual Destructor MCQs

1) What is the primary purpose of declaring a destructor as virtual in a base class?

  • Function overloading of destructors becomes possible through this declaration.
  • To support constructor inheritance
  • Deriving classes need the destructor to execute correctly when a base class pointer deletes the object.
  • To improve runtime performance

2) When should we declare base class destructors as virtual?

  • The class requires a virtual destructor if it will be used through polymorphism
  • The requirement for a virtual destructor exists only when the class contains static members.
  • The creation of objects occurs on stack memory.
  • The rule exists to mandate virtual destructors in base classes that do not have members.

a) If a class is intended to be utilized through polymorphism, it necessitates a virtual destructor.

3) Why does a pure virtual destructor require definition even when marked =0?

  • The C++ language does not enable pure virtual functions.
  • Because destructors are always called during object destruction
  • Compilers do not recognize virtual keywords in their operation.
  • Base class objects don't actually exist in reality

Option b is correct because destructors are invariably invoked when an object is being destroyed.

4) What does the virtual keyword in a destructor ensure?

  • The destructor cannot be overridden
  • Objects of derived classes are the only entities able to access the destructor.
  • During deletion, the correct derived class destructor gets invoked
  • The destructor executes faster at runtime

During removal, the appropriate destructor from the derived class is called.

5) When is a destructor in a base class not required to be virtual?

  • A derived class that does not contain a destructor will use the base class destructor.
  • When the base class is never used polymorphically
  • The class contains only public data members
  • When the destructor is defaulted

b) In cases where the base class is not utilized polymorphically

Input Required

This code uses input(). Please provide values below:

Logic Practice
Install Logic Practice
Add to home screen for a faster app-like experience