- Next chapter
- Previous chapter
- Table of contents

# Chapter 14: Inheritance

> We're always interested in getting feedback. E-mail us if you like this guide, if you think that important material is omitted, if you encounter errors in the code examples or in the documentation, if you find any typos, or generally just if you feel like e-mailing. Mail to Frank Brokken or use an e-mail form. Please state the concerned document version, found in the title.

When programming in C, it is common to view problem solutions from a top-down approach: functions and actions of the program are defined in terms of sub-functions, which again are defined in sub-sub-functions, etc.. This yields a hierarchy of code: `main()` at the top, followed by a level of functions which are called from `main()`, etc..

In C++ the dependencies between code and data can also be defined in terms of classes which are related to other classes. This looks like composition (see section 4.5), where objects of a class contain objects of another class as their data. But the relation which is described here is of a different kind: a class can be defined by means of an older, pre-existing, class. This leads to a situation in which a new class has all the functionality of the older class, and additionally introduces its own specific functionality. Instead of composition, where a given class contains another class, we mean here derivation, where a given class is another class.

Another term for derivation is inheritance: the new class inherits the functionality of an existing class, while the existing class does not appear as a data member in the definition of the new class. When speaking of inheritance the existing class is called the base class, while the new class is called the derived class.

Derivation of classes is often used when the methodology of C++ program development is fully exploited. In this chapter we will first address the syntactical possibilities which C++ offers to derive classes from other classes. Then we will address the peculiar extension to C which is thus offered by C++.

As we have seen the object-oriented approach to problem solving in the introductory chapter (see section 2.4), classes are identified during the problem analysis, after which objects of the defined classes can be declared to represent entities of the problem at hand. The classes are placed in a hierarchy, where the top-level class contains the least functionality. Each derivation and hence descent in the hierarchy adds functionality in the class definition.

In this chapter we shall use a simple vehicle classification system to build a hierarchy of classes. The first class is `Vehicle`, which implements as its functionality the possibility to set or retrieve the weight of a vehicle. The next level in the object hierarchy are land-, water- and air vehicles.

The initial object hierarchy is illustrated in figure 12.

figure 12: Initial object hierarchy of vehicles.

## 14.1: Related types

The relationship between the proposed classes representing different kinds of vehicles is further illustrated here. The figure shows the object hierarchy in vertical direction: an `Auto` is a special case of a `Land` vehicle, which in turn is a special case of a `Vehicle`.

The class `Vehicle` is thus the `greatest common denominator' in the classification system. For the sake of the example we implement in this class the functionality to store and retrieve the weight of a vehicle:

        class Vehicle
        {
            public:
                // constructors
                Vehicle();
                Vehicle(int wt);

                // interface
                int getweight() const;
                void setweight(int wt);

            private:
                // data
                int weight;
        };

Using this class, the weight of a vehicle can be defined as soon as the corresponding object is created. At a later stage the weight can be re-defined or retrieved.

To represent vehicles which travel over land, a new class `Land` can be defined with the functionality of a `Vehicle`, but in addition its own specific information. For the sake of the example we assume that we are interested in the speed of land vehicles and in their weight. The relationship between `Vehicle`s and `Land`s could of course be represented with composition, but that would be awkward: composition would suggest that a `Land` vehicle contains a vehicle, while the relationship should be that the `Land` vehicle is a special case of a vehicle.

A relationship in terms of composition would also introduce needless code. E.g., consider the following code fragment which shows a class `Land` using composition (only the `setweight()` functionality is shown):

        class Land
        {
            public:
                void setweight(int wt);
            private:
                Vehicle v;      // composed Vehicle
        };

        void Land::setweight(int wt)
        {
            v.setweight(wt);
        }

Using composition, the `setweight()` function of the class `Land` would only serve to pass its argument to `Vehicle::setweight()`. Thus, as far as weight handling is concerned, `Land::setweight()` would introduce no extra functionality, just extra code. Clearly this code duplication is redundant: a `Land` should be a `Vehicle`, and not: a `Land` should contain a `Vehicle`.

The relationship is better achieved with inheritance: `Land` is derived from `Vehicle`, in which `Vehicle` is the base class of the derivation.

        class Land: public Vehicle
        {
            public:
                // constructors
                Land();
                Land(int wt, int sp);

                // interface
                void setspeed(int sp);
                int getspeed() const;

            private:
                // data
                int speed;
        };

By postfixing the class name `Land` in its definition by `public Vehicle` the derivation is defined: the class `Land` now contains all the functionality of its base class `Vehicle` plus its own specific information. The extra functionality consists here of a constructor with two arguments and interface functions to access the `speed` data member. (The derivation in this example mentions the keyword `public`. C++ also implements `private` derivation, which is not often used and which we will therefore leave to the reader to uncover.).

To illustrate the use of the derived class `Land` consider the following example:

        Land
            veh(1200, 145);

        int main()
        {
            cout << "Vehicle weighs " << veh.getweight() << endl
                 << "Speed is " << veh.getspeed() << endl;

            return (0);
        }

This example shows two features of derivation. First, `getweight()` is no direct member of a `Land`. Nevertheless it is used in `veh.getweight()`. This member function is an implicit part of the class, inherited from its `parent' vehicle.

Second, although the derived class `Land` now contains the functionality of `Vehicle`, the `private` fields of `Vehicle` remain private in the sense that they can only be accessed by member functions of `Vehicle` itself. This means that the member functions of `Land` must use the interface functions (`getweight()`, `setweight()`) to address the `weight` field; just as any other code outside the `Vehicle` class. This restriction is necessary to enforce the principle of data hiding. The class `Vehicle` could, e.g., be recoded and recompiled, after which the program could be relinked. The class `Land` itself could remain unchanged.

Actually, the previous remark is not quite right: If the internal organization of the `Vehicle` changes, then the internal organization of the `Land` objects, containing the data of `Vehicle`, changes as well. This means that objects of the `Land` class, after changing `Vehicle`, might require more (or less) memory than before the modification. However, in such a situation we still don't have to worry about the use of memberfunctions of the parent class `Vehicle` in the class `Land`. We might have to recompile the `Land` sources, though, as the relative locations of the data members within the `Land` objects will have changed due to the modification of the `Vehicle` class.

To play it safe, classes which are derived from other classes must be fully recompiled (but don't have to be modified) after changing the data organization of their base class(es). As adding new memberfunctions to the base class doesn't alter the data organization, no such recompilation is needed after adding new memberfunctions. (A subtle point to note, however, is that adding a new memberfunction that happens to be the first virtual memberfunction of a class results in a hidden pointer to a table of pointers to virtual functions. This topic is discussed further in chapter 15).

In the following example we assume that the class `Auto`, representing automobiles, should be able to contain the weight, speed and name of a car. This class is therefore derived from `Land`:

        class Auto: public Land
        {
            public:
                // constructors
                Auto();
                Auto(int wt, int sp, char const *nm);

                // copy constructor
                Auto(Auto const &other);

                // assignment
                Auto const &operator=(Auto const &other);

                // destructor
                ~Auto();

                // interface
                char const *getname() const;
                void setname(char const *nm);

            private:
                // data
                char const *name;
        };

In the above class definition, `Auto` is derived from `Land`, which in turn is derived from `Vehicle`. This is called nested derivation: `Land` is called `Auto`'s direct base class, while `Vehicle` is called the the indirect base class.

Note the presence of a destructor, a copy constructor and overloaded assignment function in the class `Auto`. Since this class uses a pointer to reach allocated memory, these tools are needed.

## 14.2: The constructor of a derived class

As mentioned earlier, a derived class inherits the functionality from its base class. In this section we shall describe the effects of the inheritance on the constructor of a derived class.

As can be seen from the definition of the class `Land`, a constructor exists to set both the `weight` and the `speed` of an object. The poor-man's implementation of this constructor could be:

        Land::Land (int wt, int sp)
        {
            setweight(wt);
            setspeed(sp);
        }

This implementation has the following disadvantage. The C++ compiler will generate code to call the default constructor of a base class from each constructor in the derived class, unless explicitly instructed otherwise. This can be compared to the situation which arises in composed objects (see section 4.5).

Consequently, in the above implementation (a) the default constructor of a `Vehicle` is called, which probably initializes the weight of the vehicle, and (b) subsequently the weight is redefined by calling `setweight()`.

A better solution is of course to call directly the constructor of `Vehicle` expecting an `int` argument. The syntax to achieve this is to mention the constructor to be called (supplied with an argument) immediately following the argument list of the constructor of the derived class itself:

        Land::Land(int wt, int sp)
        :
            Vehicle(wt)
        {
            setspeed(sp);
        }

## 14.3: The destructor of a derived class

Destructors of classes are called automatically when an object is destroyed. This rule also holds true for objects of classes that are derived from other classes. Assume we have the following situation:

        class Base
        {
            public:
                ...         // members
                ~Base();    // destructor
        };

        class Derived
        {
            public:
                ...         // members
                ~Derived(); // destructor
        }

        ...                 // other code

        int main()
        {
            Derived
                derived;

            ...
            return (0);
        }

At the end of the `main()` function, the `derived` object ceases to exists. Hence, its destructor `Derived::~Derived()` is called. However, since `derived` is also a `Base` object, the `Base::~Base()` destructor is called as well.

It is not necessary to call the `Base::~Base()` destructor explicitly from the `Derived::~Derived()` destructor.

Constructors and destructors are called in a stack-like fashion: when `derived` is constructed, the appropriate `Base` constructor is called first, then the appropriate `Derived` constructor is called. When `derived` is destroyed, the `Derived` destructor is called first, and then the `Base` destructor is called for that object. In general, a derived class destructor is called before a base class destructor is called.

## 14.4: Redefining member functions

The actions of all functions which are defined in a base class (and which are therefore also available in derived classes) can be redefined. This feature is illustrated in this section.

Let's assume that the vehicle classification system should be able to represent trucks, which consist of a two parts: the front engine, which pulls a trailer. Both the front engine and the trailer have their own weights, but the `getweight()` function should return the combined weight.

The definition of a `Truck` therefore starts with the class definition, derived from `Auto` but expanded to hold one more `int` field to represent additional weight information. Here we choose to represent the weight of the front part of the truck in the `Auto` class and to store the weight of the trailer in an additional field:

        class Truck: public Auto
        {
            public:
                // constructors
                Truck();
                Truck(int engine_wt, int sp, char const *nm,
                      int trailer_wt);

                // interface: to set two weight fields
                void setweight(int engine_wt, int trailer_wt);
                // and to return combined weight
                int getweight() const;

            private:
                // data
                int trailer_weight;
        };

        // example of constructor
        Truck::Truck(int engine_wt, int sp, char const *nm,
                     int trailer_wt)
        :
            Auto(engine_wt, sp, nm)
        {
            trailer_weight = trailer_wt;
        }

Note that the class `Truck` now contains two functions which are already present in the base class:

- The function `setweight()` is already defined in `Auto`. The redefinition in `Truck` poses no problem: this functionality is simply redefined to perform actions which are specific to a `Truck` object.
  The definition of a new version of `setweight()` in the class `Truck` will hide the version of `Auto` (which is the version defined in `Vehicle`: for a `Truck` only a `setweight()` function with two `int` arguments can be used.
  However, note that the `Vehicle`'s `setweight()` function remains available. But, as the `Auto::setweight()` function is hidden it must be called explicitly when needed (e.g., inside `Truck::setweight()`. This is required even though `Auto::setweight()` has only one `int` argument, and one could argue that `Auto::setweight()` and `Truck::setweight()` are merely overloaded functions within the class `Truck`. So, the implementation of the function `Truck::setweight()` could be:

          void Truck::setweight(int engine_wt, int trailer_wt)
          {
              trailer_weight = trailer_wt;
              Auto::setweight(engine_wt);     // note: Auto:: is required
          }

- Outside of the class the `Auto`-version of `setweight()` is accessed through the scope resolution operator. So, if a `Truck t` needs to set its `Auto` weight, it must use
  `t.Auto::setweight(x)`
- An alternative to using the scope resolution operator is to include the base-class functions in the class interface as inline functions. This might be an elegant solution for the occasional function. E.g., if the interface of the `class Truck` contains

          void setweight(int engine_wt)
          {
              Auto::setweight(engine_wt);
          }

  then the single argument `setweight()` function can be used by `Truck` objects without using the scope resolution operator. As the function is defined inline, no overhead of an extra function call is involved.
- The function `getweight()` is also already defined in `Vehicle`, with the same argument list as in `Truck`. In this case, the class `Truck` redefines this member function.

  The next code fragment presents the redefined function `Truck::getweight()`:

          int Truck::getweight() const
          {
              return
                  (                           // sum of:
                      Auto::getweight() +     //   engine part plus
                      trailer_weight          //   the trailer
                  );
          }

The following example shows the actual usage of the member functions of the class `Truck` to display several of its weights:

        int main()
        {
            Land
                veh(1200, 145);

            Truck
                lorry(3000, 120, "Juggernaut", 2500);

            lorry.Vehicle::setweight(4000);

            cout << endl << "Truck weighs " << lorry.Vehicle::getweight() << endl
                << "Truck + trailer weighs " << lorry.getweight() << endl
                << "Speed is " << lorry.getspeed() << endl
                << "Name is " << lorry.getname() << endl;
            return (0);
        }

Note the explicit call to `Vehicle::setweight(4000)`: in order to reach the hidden memberfunction `Vehicle::setweight()`, which is part of the set of memberfunctions available to the class `Vehicle`, is must be called explicitly, using the `Vehicle::` scope resolution. As said, this is remarkable, because `Vehicle::setweight()` can very well be considered an overloaded version of `Truck::setweight()`. The situation with `Vehicle::getweight()` and `Truck::getweight()` is a different one: here the function `Truck::getweight()` is a redefinition of `Vehicle::getweight()`, so in order to reach `Vehicle::getweight()` a scope resolution operation (`Vehicle::`) is required.

## 14.5: Multiple inheritance

In the previously described derivations, a class was always derived from one base class. C++ also implements multiple derivation, in which a class is derived from several base classes and hence inherits the functionality from more than one `parent' at the same time.

For example, let's assume that a class `Engine` exists with the functionality to store information about an engine: the serial number, the power, the type of fuel, etc.:

        class Engine
        {
            public:
                // constructors and such
                Engine();
                Engine(char const *serial_nr, int power,
                       char const *fuel_type);

                // tools needed as we have pointers in the class
                Engine(Engine const &other);
                Engine const &operator=(Engine const &other);

                ~Engine();

                // interface to get/set stuff
                void setserial(char const *serial_nr);
                void setpower(int power);
                void setfueltype(char const *type);

                char const *getserial() const;
                int getpower() const;
                char const *getfueltype() const;

            private:
                // data
                char const
                    *serial_number,
                    *fuel_type;
                int
                    power;
        };

To represent an `Auto` but with all information about the engine, a class `MotorCar` can be derived from `Auto` `and` from `Engine`, as illustrated in the below listing. By using multiple derivation, the functionality of an `Auto` and of an `Engine` are combined into a `MotorCar`:

        class MotorCar
        :
            public Auto,
            public Engine
        {
            public:
                // constructors
                MotorCar();
                MotorCar(int wt, int sp, char const *nm,
                         char const *ser, int pow, char const *fuel);
        };

        MotorCar::MotorCar(int wt, int sp, char const *nm,
                           char const *ser, int pow, char const *fuel)
        :
            Engine (ser, pow, fuel),
            Auto (wt, sp, nm)
        {
        }

A few remarks concerning this derivation are:

- The keyword `public` is present both before the classname `Auto` and before the classname `Engine`. This is so because the default derivation in C++ is `private`: the keyword `public` must be repeated before each base class specification.

- The multiply derived class `MotorCar` introduces no `extra' functionality of its own, but only combines two pre-existing types into one aggregate type. Thus, C++ offers the possibility to simply sweep multiple simple types into one more complex type.

  This feature of C++ is very often used. Usually it pays to develop `simple' classes each with its strict well-defined functionality. More functionality can always be achieved by combining several small classes.

- The constructor which expects six arguments contains no code of its own. Its only purpose is to activate the constructors of the base classes. Similarly, the class definition contains no data or interface functions: here it is sufficient that all interface is inherited from the base classes.

Note also the syntax of the constructor: following the argument list, the two base class constructors are called, each supplied with the correct arguments. It is also noteworthy that the order in which the constructors are called is defined by the interface, and not by the implementation (i.e., by the statement in the constructor of the class `MotorCar`. This implies that:

- First, the constructor of `Auto` is called, since `MotorCar` is first of all derived from `Auto`.

- Then, the constructor of `Engine` is called,

- Last, any actions of the constructor of `MotorCar` itself are executed (in this example, none).

Lastly, it should be noted that the multiple derivation in this example may feel a bit awkward: the derivation implies that `MotorCar` is an `Auto` and at the same time it is an `Engine`. A relationship `a `MotorCar` has an `Engine`' would be expressed as composition, by including an `Engine` object in the data of a `MotorCar`. But using composition, unnecessary code duplication occurs in the interface functions for an `Engine` (here we assume that a composed object `engine` of the class `Engine` exists in a `MotorCar`):

        void MotorCar::setpower(int pow)
        {
            engine.setpower(pow);
        }

        int MotorCar::getpower() const
        {
            return (engine.getpower());
        }

        // etcetera, repeated for set/getserial(),
        // and set/getfueltype()

Clearly, such simple interface functions are avoided completely by using derivation. Alternatively, when insisting on the `has` relationship and hence on composition, the interface functions could have been avoided by using `inline` functions.

## 14.6: Conversions between base classes and derived classes

When inheritance is used in the definition of classes, it can be said that an object of a derived class is at the same time an object of the base class. This has important consequences for the assignment of objects, and for the situation where pointers or references to such objects are used. Both situations will be discussed next.

### 14.6.1: Conversions in object assignments

We define two objects, one of a base class and one of a derived class:

        Vehicle
            v(900);                 // vehicle with weight 900 kg
        Auto
            a(1200, 130, "Ford");   // automobile with weight 1200 kg,
                                    // max speed 130 km/h, make Ford

The object `a` is now initialized with its specific values. However, an `Auto` is at the same time a `Vehicle`, which makes the assignment from a derived object to a base object possible:

        v = a;

The effect of this assignment is that the object `v` now receives the value 1200 as its `weight` field. A `Vehicle` has neither a `speed` nor a `name` field: these data are therefore not assigned.

The conversion from a base object to a derived object, however, is problematic: In a statement like

        a = v;

it isn't clear what data to enter into the fields `speed` and `name` of the `Auto` object `a`, as they are missing in the `Vehicle` object `v`. Such an assignment is therefore not accepted by the compiler.

The following general rule applies: when assigning related objects, an assignment in which some data are dropped is legal. However, an assignment where data would have to be left blank is not legal. This rule is a syntactic one: it also applies when the classes in question have their overloaded assignment functions.

The conversion of an object of a base class to an object of a derived class could of course be explicitly defined using a dedicated constructor. E.g., to achieve compilability of a statement

        a = v;

the class `Auto` would need an assignment function accepting a `Vehicle` as its argument. It would be the programmer's responsibility to decide what to do with the missing data:

        Auto const &Auto::operator=(Vehicle const &veh)
        {
            setweight (veh.getweight());
            .
            .  code to handle other fields should
            .  be supplied here
            .
        }

### 14.6.2: Conversions in pointer assignments

We define the following objects and one pointer variable:

        Land
            land(1200, 130);
        Auto
            auto(500, 75, "Daf");
        Truck
            truck(2600, 120, "Mercedes", 6000);
        Vehicle
            *vp;

Subsequently we can assign `vp` to the addresses of the three objects of the derived classes:

        vp = &land;
        vp = &auto;
        vp = &truck;

Each of these assignments is perfectly legal. However, an implicit conversion of the type of the derived class to a `Vehicle` is made, since `vp` is defined as a pointer to a `Vehicle`. Hence, when using `vp` only the member functions which manipulate the `weight` can be called, as this is the only functionality of a `Vehicle` and thus it is the only functionality which is available when a pointer to a `Vehicle` is used.

The same reasoning holds true for references to `Vehicles`. If, e.g., a function is defined with a `Vehicle` reference parameter, the function may be passed an object of a class that is derived from `Vehicle`. Inside the function, the specific `Vehicle` members of the object of the derived class remain accessible. This analogy between pointers and references holds true in all cases. Remember that a reference is nothing but a pointer in disguise: it mimics a plain variable, but is actually a pointer.

This restriction in functionality has furthermore an important effect for the class `Truck`. After the statement `vp = &truck`, `vp` points to a `Truck` object. Nevertheless, `vp->getweight()` will return 2600; and not 8600 (the combined weight of the cabin and of the trailer: 2600 + 6000), which would have been returned by `t.getweight()`.

When a function is called via a pointer to an object, then the type of the pointer and not the object itself determines which member functions are available and executed. In other words, C++ implicitly converts the type of an object reached via a pointer to the type of the pointer pointing to the object.

There is of course a way around the implicit conversion, which is an explicit type cast:

        Truck
            truck;
        Vehicle
            *vp;

        vp = &truck;        // vp now points to a truck object

        Truck
            *trp;

        trp = (Truck *) vp;
        printf ("Make: %s\n", trp->getname());

The second to last statement of the code fragment above specifically casts a `Vehicle *` variable to a `Truck *` in order to assign the value to the pointer `trp`. This code will only work if `vp` indeed points to a `Truck` and hence a function `getname()` is available. Otherwise the program may show some unexpected behavior.

## 14.7: Storing base class pointers

The fact that pointers to a base class can be used to reach derived classes can be used to develop general-purpose classes which can process objects of the derived types. A typical example of such processing is the storage of objects, be it in an array, a list, a tree or whichever storage method may be appropriate. Classes which are designed to store objects of other classes are therefore often called container classes. The stored objects are contained in the container class.

As an example we present the class `VStorage`, which is used to store pointers to `Vehicle`s. The actual pointers may be addresses of `Vehicle`s themselves, but also may refer to derived types such as `Auto`s.

The definition of the class is the following:

        class VStorage
        {
            public:
                VStorage();
                VSTorage(VStorage const &other);
                ~VStorage();
                VStorage const &operator=(VStorage const &other);

                                    // add Vehicle& to storage
                void add(Vehicle const &vehicle);
                                    // retrieve first Vehicle *
                Vehicle const *getfirst() const;
                                    // retrieve next Vehicle *
                Vehicle const *getnext() const;

            private:
                // data
                Vehicle
                    **storage;
                int
                    nstored,
                    current;
        };

Concerning this class definition we note:

- The class contains three interface functions: one to add a `Vehicle &` to the storage, one to retrieve the first `Vehicle *` from the storage, and one to retrieve next pointers until no more are in the storage.

  An illustration of the use of this class is given in the next example:

              Land
                  land(200, 20);          // weight 200, speed 20
              Auto
                  auto(1200, 130, "Ford");// weight 1200 , speed 130,
                                          // make Ford
              VStorage
                  garage;                 // the storage

              garage.add(land);           // add to storage
              garage.add(auto);

              Vehicle const
                  *anyp;
              int
                  total_wt = 0;

              for (anyp = garage.getfirst(); anyp; anyp = garage.getnext())
                  total_wt += anyp->getweight();

              cout << "Total weight: " << total_wt << endl;

  This example demonstrates how derived types (one `Auto` and one `Land`) are implicitly converted to their base type (a `Vehicle &`), so that they can be stored in a `VStorage`. Base-type objects are then retrieved from the storage. The function `getweight()`, defined in the base class and the derived classes, is therupon used to compute the total weight.

- Furthermore, the class `VStorage` contains all the tools to ensure that two `VStorage` objects can be assigned to one another etc.. These tools are the overloaded assignment function and the copy constructor.

- The actual internal workings of the class only become apparent once the `private` section is seen. The class `VStorage` maintains an array of pointers to `Vehicle`s and needs two `int`s to store how many objects are in the storage and which the `current' index is, to be returned by `getnext()`.

The class `VStorage` shall not be further elaborated; similar examples shall appear in the next chapters. It is however very noteworthy that by providing class derivation and base/derived conversions, C++ presents a powerful tool: these features of C++ allow the processing of all derived types by one generic class.

The above class `VStorage` could even be used to store all types which may be derived from a `Vehicle` in the future. It seems a bit paradoxical that the class should be able to use code which isn't even there yet, but there is no real paradox: `VStorage` uses a certain protocol, defined by the `Vehicle` and obligatory for all derived classes.

The above class `VStorage` has just one disadvantage: when we add a `Truck` object to a storage, then a code fragment like:

        Vehicle const
            *any;
        VStorage
            garage;

        any = garage.getnext();
        cout << any->getweight() << endl;

will not print the truck's combined weight of the cabin and the trailer. Only the weight stored in the `Vehicle` portion of the truck will be returned via the function `any->getweight()`. Fortunately, there is a remedy against this slight disadvantage. This remedy will be discussed in the next chapter.

- Next chapter
- Previous chapter
- Table of contents