When you want to delete an instance of a derived class using a pointer to the base class, virtual destructors come in handy:
// some virtual methods
class Derived : public Base
// Do some important cleanup
You'll notice that I didn't make Base's destructor virtual in this case.
Take a look at the following snippet now:
Base *b = new Derived();
// use b
delete b; // Here's the problem!
Delete b has undefined behaviour because Base's destructor is not virtual and b is a Base* pointing to a Derived object:
If the object to be deleted's static type is different from its dynamic type, the static type must be a base class of the object's dynamic type, and the static type must have a virtual destructor, or the behaviour is undefined.
In most implementations, the call to the destructor is resolved like any non-virtual code, which means that the base class's destructor is called but not the derived class's, resulting in a resource leak.
To summarise, whenever base classes are meant to be manipulated polymorphically, make their destructors virtual.
If you want to prevent an instance from being deleted through a base class pointer, make the base class destructor protected and nonvirtual; the compiler will not allow you to call delete on a base class pointer if you do so.