Inheritance Recap

Inheritance is how C++ models an is-a relationship: a Rifle is a Weapon, so Rifle can be built on top of Weapon rather than repeating everything Weapon already provides. This chapter covered how that relationship is declared, what the derived class receives, the order in which the pieces are built and torn down, and how much of the base class stays visible.

The Vocabulary

Each side of the relationship answers to three interchangeable names:

Role Names
Supplies the members parent class, base class, superclass
Receives them child class, derived class, subclass

Different books and codebases prefer different pairs, so all six turn up in practice.

A derived class acquires every member of its base class. The derived object physically contains a base portion, and the members declared in the derived class sit alongside it.

Construction and Destruction Order

The base portion is always constructed before the derived portion, because the derived class is entitled to use base members in its own constructor. Step by step:

  1. Memory is set aside for the whole object, base portion and derived portion together.
  2. The selected derived class constructor is entered.
  3. The base class is constructed first, using whichever base constructor the derived constructor names. Naming none selects the base class default constructor.
  4. The derived class member initializer list initializes the derived members.
  5. Finally the derived constructor's own body executes.
  6. Control returns to the caller.

Destruction runs the sequence backwards, from most-derived to most-base. This is not a detail you have to memorise, because a short program will show it to you:

#include <iostream>

class Weapon
{
public:
    Weapon() { std::cout << "Weapon constructed\n"; }
    ~Weapon() { std::cout << "Weapon destroyed\n"; }
};

class Rifle : public Weapon
{
public:
    Rifle() { std::cout << "Rifle constructed\n"; }
    ~Rifle() { std::cout << "Rifle destroyed\n"; }
};

int main()
{
    Rifle rifle{};

    return 0;
}

Output:

Weapon constructed
Rifle constructed
Rifle destroyed
Weapon destroyed

With a longer chain the same rule applies: construction runs from the most-base class down to the most-derived, and destruction from the most-derived back up to the most-base.

Access Specifiers and Inheritance Types

C++ has three access specifiers. public members are reachable by anyone, private members only by the class itself and its friends, and protected members by the class, its friends, and its derived classes, but not by outside code. protected exists specifically for the middle case: something a subclass needs but the public should not touch.

Inheritance itself comes in three forms, public, private, and protected, and the form you pick caps how visible each inherited member becomes. Public is what you want in almost every case, since it is the only one that preserves the is-a relationship for outside code:

Access in the base class Inherited publicly Inherited privately Inherited protectedly
Public Public Private Protected
Protected Protected Private Protected
Private Inaccessible Inaccessible Inaccessible

Private members of the base class are never accessible in the derived class regardless of the inheritance type. The derived object still contains them, but only the base class can reach them.

Changing What You Inherit

A derived class is not limited to accepting the base class as it is. It can add functions that the base does not have, change what an inherited function does for the derived type, adjust the access level of an inherited member, and hide base class functionality it does not want exposed.

Multiple Inheritance

A class may name more than one base in its declaration, which is multiple inheritance. It is supported, but treat it as a last resort: reach for it only when every alternative produces more complexity than it removes.

Terms Used in This Chapter

  • Inheritance: acquiring the members of another class
  • Base class, parent class, superclass: the class being inherited from
  • Derived class, child class, subclass: the class doing the inheriting
  • Is-a relationship: the relationship inheritance is meant to express
  • protected: access for the class, its friends, and its derived classes, but not the public
  • Public inheritance: public members stay public and protected stay protected, the default choice
  • Private inheritance: every accessible inherited member becomes private
  • Protected inheritance: public members become protected
  • Multiple inheritance: inheriting from more than one base class

Looking Forward

You now have the mechanics: what is inherited, in what order it is built and destroyed, and who can see what. What is still missing is the part that makes inheritance powerful at run time, which is choosing behavior based on the actual type of an object rather than the type of the pointer or reference holding it. That is polymorphism, and it comes next, along with virtual functions and abstract base classes.