class Base // Base Class
{
	public:
		~Base () {} // Destructor for Base()
};
 
class Derived : public Base // Derived Class
{
	public:
		~Derived () {} // Destructor for Derived()
};
 
Base *obj = new Derived(); // Create Base pointer that points to Derived
 
// Things go wrong here!
delete obj; 

When obj is being deleted, the destructor for Base will be invoked. This is dangerous because it leaks memory Derived’s destructor is not called, hence the contents of the Derived class will remain dangling Virtual destructors make sure that the right destructors are invoked in an intuitive manner

class Base // Base Class
{
	public:
		virtual ~Base () {} // Destructor for Base()
};
 
class Derived : public Base // Derived Class
{
	public:
		~Derived () {} // Destructor for Derived()
};
 
Base *obj = new Derived(); // Create Base pointer that points to Derived
 
// All good!
delete obj; 

Here, when obj is being deleted, the destructor of Derived will first be called and then Base’s destructor is called, thus ensuring no memory leaks and a safe cleanup.