If destructors are defined for a base and a derived class, they are executed in the reverse order that the constructors are executed. When an object of a derived class goes out of scope, the destructor for the derived class is called and then the destructor for the base class is called.
When destroying dynamically created objects with the delete operator, a problem can arise. If delete is applied to a base class pointer, the compiler calls the base class destructor, even if the pointer points to an instance of a derived class.
The solution is to declare the base class's destructor as virtual. This causes the destructors of all derived classes to be virtual, even though they don't share the same name as the base class's destructor. Then if delete is applied to a base class pointer, the appropriate destructor is called, no matter what type of object the pointer is pointing to.
Notice that Employee has a virtual destructor, even though the destructor does nothing. Whenever you write a class that has virtual functions, you always should give it a virtual destructor, even if the class doesn't need one. The reason is that a derived class might require a destructor. For example, suppose you derive a class from Employee called Consultant, and that derived class defines a destructor. By defining a virtual destructor in the base class, you ensures that the derived class's destructor is called when needed.
Note that while destructor functions can be virtual, constructor functions cannot.