
- C++ Home
- C++ Overview
- C++ Environment Setup
- C++ Basic Syntax
- C++ Comments
- C++ Hello World
- C++ Omitting Namespace
- C++ Tokens
- C++ Constants/Literals
- C++ Keywords
- C++ Identifiers
- C++ Data Types
- C++ Numeric Data Types
- C++ Character Data Type
- C++ Boolean Data Type
- C++ Variable Types
- C++ Variable Scope
- C++ Multiple Variables
- C++ Input Output Operations
- C++ Basic Input/Output
- C++ Cin
- C++ Cout
- C++ Manipulators
- Type System & Data Representation
- C++ Modifier Types
- C++ Storage Classes
- C++ Constexpr Specifier
- C++ Numbers
- C++ Enumeration
- C++ Enum Class
- C++ References
- C++ Date & Time
- C++ Operators
- C++ Operators
- C++ Arithmetic Operators
- C++ Relational Operators
- C++ Logical Operators
- C++ Bitwise Operators
- C++ Assignment Operators
- C++ sizeof Operator
- C++ Conditional Operator
- C++ Comma Operator
- C++ Member Operators
- C++ Casting Operators
- C++ Pointer Operators
- C++ Operators Precedence
- C++ Unary Operators
- C++ Scope Resolution Operator
- C++ Control Statements
- C++ Decision Making
- C++ if Statement
- C++ if else Statement
- C++ Nested if Statements
- C++ switch Statement
- C++ Nested switch Statements
- C++ Loop Types
- C++ while Loop
- C++ for Loop
- C++ do while Loop
- C++ Foreach Loop
- C++ Nested Loops
- C++ Jump Statements
- C++ break Statement
- C++ continue Statement
- C++ goto Statement
- C++ Return Values
- C++ Strings
- C++ Strings
- C++ Loop Through a String
- C++ String Length
- C++ String Concatenation
- C++ String Comparison
- C++ Functions
- C++ Functions
- C++ Multiple Function Parameters
- C++ Recursive Function
- C++ Function Overloading
- C++ Function Overriding
- C++ Default Arguments
- C++ Arrays
- C++ Arrays
- C++ Multidimensional Arrays
- C++ Pointer to an Array
- C++ Passing Arrays to Functions
- C++ Return Array from Functions
- C++ Array Decay
- C++ Structure & Union
- C++ Structures
- C++ Unions
- C++ Class and Objects
- C++ Object Oriented
- C++ Classes & Objects
- C++ Class Member Functions
- C++ Class Access Modifiers
- C++ Static Class Members
- C++ Static Data Members
- C++ Static Member Function
- C++ Inline Functions
- C++ this Pointer
- C++ Friend Functions
- C++ Pointer to Classes
- C++ Constructors
- C++ Constructor & Destructor
- C++ Default Constructors
- C++ Parameterized Constructors
- C++ Copy Constructor
- C++ Constructor Overloading
- C++ Constructor with Default Arguments
- C++ Delegating Constructors
- C++ Constructor Initialization List
- C++ Dynamic Initialization Using Constructors
- C++ Destructors
- C++ Virtual Destructor
- C++ Inheritance
- C++ Inheritance
- C++ Multiple Inheritance
- C++ Multilevel Inheritance
- C++ Object-oriented
- C++ Overloading
- C++ Polymorphism
- C++ Abstraction
- C++ Encapsulation
- C++ Interfaces
- C++ Virtual Function
- C++ Pure Virtual Functions & Abstract Classes
- C++ Override Specifiers
- C++ Final Specifiers
- C++ Design Patterns
- C++ Creational Design Patterns
- C++ Singleton Design Pattern
- C++ Factory Method Design Pattern
- C++ Abstract Factory Pattern
- C++ Prototype Design Pattern
- C++ Structural Design Patterns
- C++ File Handling
- C++ Files and Streams
- C++ Reading From File
- C++ Advanced
- C++ Exception Handling
- C++ Dynamic Memory
- C++ Namespaces
- C++ Templates
- C++ Preprocessor
- C++ Signal Handling
- C++ Multithreading
- C++ Web Programming
- C++ Socket Programming
- C++ Concurrency
- C++ Advanced Concepts
- C++ Lambda Expression
- C++ nullptr
- C++ unordered_multiset
- C++ Structural Design Patterns
- C++ Adapter Pattern
- C++ Bridge Pattern
- C++ Composite Pattern
- C++ Decorator Pattern
Virtual Destructor in C++
A virtual destructor is a destructor declared within the base class with the virtual keyword. When deleting a derived class object using a pointer to a base class, the base class should be defined with a virtual destructor.
Virtual destructors help prevent the problem of memory leaks and undefined behavior. If a virtual destructor is not used, then only the base class destructor is called, and the resources of derived class is not cleaned up.
The Syntax for declaring a virtual destructor is given below −
class Base { public: virtual ~Base() { // base class destructor } };
Example
The following example demonstrates how to use a virtual destructor. The virtual destructor calls the destructor of both classes i.e. base and child class −
#include <iostream> using namespace std; class Base { public: Base() { cout << "Base Constructor\n"; } virtual ~Base() { cout << "Base Destructor\n"; } }; class Derived : public Base { public: Derived() { cout << "Derived Constructor\n"; } ~Derived() { cout << "Derived Destructor\n"; } }; int main() { Base *basePtr = new Derived(); delete basePtr; return 0; }
The output of the above code is given below −
Base Constructor Derived Constructor Derived Destructor Base Destructor
Why We Need Virtual Destructors?
Given below are the reasons why virtual destructors are needed −
- When you do not use a virtual base class destructor while deleting a derived class object, it results in undefined behavior.
- Virtual destructors make sure to delete the object of derived class too while deleting the base class object.
- It avoids memory leak.
- Virtual destructors maintain the order of execution of destructors i.e., first derived class, then base class.
Example: Non-Virtual Destructor
In the following example, the virtual destructor is not used. In the output, it can be observed that only the base class destructor has been called and the destructor of derived class is skipped.
#include <iostream> using namespace std; class Base { public: // Non-virtual destructor ~Base() { cout << "Base class destructor called.\n"; } }; class Derived : public Base { public: ~Derived() { cout << "Derived class destructor also called.\n"; } }; int main() { Base* ptr = new Derived(); // Only Base destructor will be called delete ptr; return 0; }
The output of the above code is given below −
Base class destructor called.
Example: Virtual Destructor
In this example, we have used a virtual destructor on base class Base. In the output, it can be observed that the destructor of both base and derived class is called and it maintains the reverse order of deletion.
#include <iostream> using namespace std; class Base { public: // Virtual destructor virtual ~Base() { cout << "Base class destructor called.\n"; } }; class Derived : public Base { public: ~Derived() { cout << "Derived class destructor also called.\n"; } }; int main() { Base* ptr = new Derived(); // Both Base class and derived class destructor will be called delete ptr; return 0; }
The output of the above code is given below −
Derived class destructor also called. Base class destructor called.
When to Use Virtual Destructors?
You can use a virtual destructor in the following scenarios.
- If a virtual function is used, then use virtual destructor. Since, virtual functions are used in polymorphism to override base class. Using a virtual destructor can free up memory of both, base and derived class.
- In inheritance, make the destructor of base class a virtual destructor as the destructor of derived class is skipped and only the base class destructor is called, it may cause a memory leak.
- If abstract base or pure virtual function is used, then use virtual destructor on base class.
Virtual Destructor Table (Vtable)
In C++, virtual table(vtable) is a lookup table which is used by the compiler to implement virtual functions or virtual destructors. For each class that has at least one virtual function or virtual destructor, the compiler will create a vtable for that class.
A vtable has pointers to all virtual functions and the virtual destructor of a class. In a class, each object has a hidden pointer known as vptr or virtual pointer. This vptr points to the vtable of the class, which is then used to call the respective destructor. Here is a diagram representation of the vtable for the given code −

Example
In this example, we have implemented the above code snippet to override the virtual functions of class A in class B and class C.
#include <iostream> using namespace std; class A { public: virtual void f1() { cout << "A::f1 called" << endl; } virtual void f2() { cout << "A::f2 called" << endl; } virtual ~A() { cout << "Class A destructor called" << endl; } }; class B : public A { public: void f1() override { cout << "B::f1 called" << endl; } void f2() override { cout << "B::f2 called" << endl; } ~B() override { cout << "Class B destructor called" << endl; } }; class C : public A { public: void f1() override { cout << "C::f1 called" << endl; } void f2() override { cout << "C::f2 called" << endl; } ~C() override { cout << "Class C destructor called" << endl; } }; int main() { A* ptrB = new B(); A* ptrC = new C(); cout << "Calling functions using pointer B:" << endl; ptrB->f1(); ptrB->f2(); cout << "Calling functions using pointer C:" << endl; ptrC->f1(); ptrC->f2(); // Calling B's destructor then A's destructor delete ptrB; // Calling C's destructor then A's destructor delete ptrC; return 0; }
The output of the above code is given below −
Calling functions using pointer B: B::f1 called B::f2 called Calling functions using pointer C: C::f1 called C::f2 called Class B destructor called Class A destructor called Class C destructor called Class A destructor called
Conclusion
The virtual destructor is used when working with inheritance and polymorphism. Its main purpose is to make sure that the destructors of derived classes are also called when an object is deleted through a base class pointer. This prevents memory leaks and undefined behavior.