X::X()
Y::Y()
Y::~Y()
X::~X()
Now that the destructors are virtual, dynamic dispatch occurs for the invocation
of destructor. Even though xptr has been declared as a pointer to X, it points to an object of class Y.
delete xptr;
invokes the destructor Y::~Y(). And since Y is derived from X, it goes on to
invoke the destructor X::~X() See this earlier
example, if you are not clear on this
The lesson from this exercise is that you should always make
your destructors virtual unless you have a strong reason for not doing so.