Appendix A. Virtual Default Destructor
So as not to disrupt the first pass through the modern context review of object inheritance in Chapter 3, discussion of the reasons for including a virtual default destructor in this context has been deferred to this appendix. We will now look at an example to demonstrate why one should be included in a base class.
Suppose we have two classes, Base and Derived, defined as follows. A virtual trig_fcn(.) on Base will compute the sine of a number, and its override on Derived will compute the cosine (objects of these classes are also used in Appendix B, where their member functions will actually be called). For this simple example, we just put the implementation inside the declaration:
#include <cmath>
#include <iostream>
class Base
{
public:
virtual double trig_fcn(double x) const
{
return std::cos(x);
}
~Base() {std::cout << "Base destructor called\n";}
};
class Derived final : public Base
{
public:
double trig_fcn(double x) const override
{
return std::sin(x);
}
~Derived() {std::cout << "Derived destructor called\n";}
};
Note that instead of the virtual destructor on the base class, each has its own destructor. The problem we encounter is related to cases where pointers to objects of these classes are defined. Supposed we define the following pointers:
Derived* d = new Derived{};
Base* b = new Base{};
Base* bd = new Derived{};
When a Derived object is created, a Base object will be constructed first, followed by its inheriting Derived object. ...