When you delete an object, there are two ways C++ might decide what destructor function to call.
If the pointer to that object has been declared to be of type T*
, but T::~T()
is a virtual function, then C++ looks in a virtual function table to find which destructor to call. The virtual function table is found via a pointer stored within the memory of that instance of the object, which is determined by the class that was actually constructed, not by the type of the pointer. For the object initialized by base* aPointer = new der
, if ~base()
had been declared virtual, C++ would be able to look in the virtual function table of the actual concrete class (der
, not base
), and when it did so, it would find the destructor function ~der()
. This would delete name
and then would call the destructor defined by the class der
was derived from; that is, it would call ~base()
, which deletes ptr
. If base
had been derived from some other class, its destructor would call that class's destructor, and so on until reaching a class that was not derived from anything.
But if the pointer to the object has been declared to be of type T*
, and the destructor of T
is not virtual, then the only destructor the compiler can use is the one that was defined when you defined T
, namely, T::~T()
. So, because aPointer
was declared to be a base*
, delete aPointer
will first call ~base()
, which deletes ptr
, and then it returns, because there are no further base classes whose destructors can be called. The destructor ~der()
is never called in this case, so name
is not deleted. That's a memory leak.