Reliable Software Logo

C++ In Action: Language

Inheritance

Public inheritance, initialization of the base class, order of construction/destruction, type double.


Another important relationship between objects is the "is-a" relationship. When we say that a star is a celestial body, we mean that a star has all the properties of a celestial body, and maybe some others, specific to a star. In C++ this relationship is expressed using inheritance. We can say: class Star inherits from class CelestialBody, or that CelestialBody is the base class of Star.

is-a

Figure 5 Graphical representation the is-a relationships between objects.


Here's an example:

#include <iostream>

class CelestialBody
{
public:
    CelestialBody (double mass)
        : _mass (mass)
    {
        std::cout << "Creating celestial body of mass " << _mass << "\n";
    }

    ~CelestialBody ()
    {
        std::cout << "Destroying celestial body of mass " << 
            _mass << "\n";
    }

private:
    const double _mass;
};

class Star: public CelestialBody  // Star is a CelestialBody
{
public:
    Star (double mass, double brightness)
        : CelestialBody (mass), _brightness (brightness)
    {
        std::cout << "Creating a star of brightness " << 
              _brightness << "\n";
    }

    ~Star ()
    {
        std::cout << "Destroying a star of brightness " << 
            _brightness << "\n";
    }

private:
    const double _brightness;
};

int main ()
{
    std::cout << "    Entering main.\n";
    Star aStar ( 1234.5, 0.1 );
    std::cout << "    Exiting main.\n";
}

The line

class Star: public CelestialBody  // Star is a CelestialBody
tells the compiler that Star inherits everything from CelestialBody. In particular, since CelestialBody has _mass, Star will have _mass, too.

CelestialBody has a constructor that requires an argument of the type double. Double is a built in type corresponding to double precision floating point numbers. Its single precision counterpart is called a float. Notice that our clever object std::cout has no problem printing doubles.

In the preamble to the constructor of Star we have to pass the argument to the constructor of CelestialBody. Here's how we do it-we invoke the base constructor using the name of its class:

    Star (double mass, double brightness)
        : CelestialBody (mass), _brightness (brightness)

Understanding the order of construction is very important.

First the base class is fully constructed, then the derived class.

The construction of the derived class proceeds in the usual order: first the embeddings, then the code in the constructor. Again, the order in the preamble is meaningless, and if there are no explicit initializations the whole thing may be omitted. I could have written the preamble in the reverse order:

    Star (double mass, double brightness)
        : _brightness (brightness), CelestialBody (mass)
and still, the constructor for CelestialBody would have been called before the initialization of _brightness (not that I would recommend this style!).

The order of destruction is again the reverse of the order of construction. In particular, the derived class destructor is called first, the destructor of the base class follows.


NextNext: Member Functions and Interfaces