Inheritance

Introduction

Inheritance builds a new class on an existing one. class Dog : public Animal means a Dog is an Animal, with everything an Animal has, plus more. The shared code lives once, in the base class; the derived class adds or changes what is different.

Many classes share most of their code. Inheritance writes the shared part once in a base class, and each derived class adds only what makes it different.

How it works

Base and derived classes

#include <iostream>
#include <string>
using namespace std;

class Animal {
protected:
    string name;
public:
    Animal(string n) : name(n) {}
    void eat() {
        cout << name << " is eating" << endl;
    }
};

class Dog : public Animal {
    int tricks;
public:
    Dog(string n) : Animal(n), tricks(0) {}
    void fetch() {
        tricks++;
        cout << name << " fetches the ball (" << tricks << ")" << endl;
    }
};

int main() {
    Dog rex("Rex");
    rex.eat();
    rex.fetch();
    rex.fetch();
    return 0;
}
Open in compiler
  • A Dog object contains an Animal part. In the visualizer, rex shows name (from Animal) and tricks (its own) side by side, because the base part sits inside the derived object.
  • rex.eat() calls the inherited Animal::eat; rex.fetch() is Dog's own.
  • protected members are like private ones, except that derived classes may use them: Dog::fetch reads name.

Access and the "is a" test

Base memberin the derived classoutside, through the derived object
publicyesyes (with : public inheritance)
protectedyesno
privatenono

Use inheritance only when the derived class really is a kind of the base: a Car is a Vehicle. A Car has an Engine, so the engine should be a member, not a base class (composition).

Syntax

class Base {
protected:
    int shared;
public:
    Base(int s) : shared(s) {}
};

class Derived : public Base {
public:
    Derived() : Base(5) {}    // choose the base constructor
};

Example

#include <iostream>
using namespace std;

class Vehicle {
public:
    int wheels;
    Vehicle(int w) : wheels(w) {
        cout << "Vehicle with " << wheels << " wheels" << endl;
    }
    ~Vehicle() {
        cout << "~Vehicle" << endl;
    }
};

class Car : public Vehicle {
public:
    Car() : Vehicle(4) {
        cout << "Car" << endl;
    }
    ~Car() {
        cout << "~Car" << endl;
    }
};

int main() {
    Car c;
    cout << c.wheels << " wheels" << endl;
    return 0;
}
Open in compiler

Building a derived object runs the base constructor first, then the derived one: the base part must exist before the derived part builds on it. The derived constructor chooses which base constructor runs with : Base(args) in its initializer list. Destruction runs in reverse: derived first, then base. Watch the frames: Car::Car calls Vehicle::Vehicle before its own body runs.

Line by line

  1. Vehicle has a public wheels member, and its constructor and destructor each print a line.
  2. Car derives from Vehicle with : public Vehicle.
  3. Car() passes 4 to the base constructor with : Vehicle(4), so Vehicle with 4 wheels is printed before Car.
  4. c.wheels works, because the public base member is part of every Car.
  5. When main ends, ~Car runs first and then ~Vehicle, the reverse of construction.

Expected result

Vehicle with 4 wheels
Car
4 wheels
~Car
~Vehicle

In the real world

GUI toolkits derive every button, text box and window from a common widget class. Game engines often derive game objects from a shared base that holds a position, so every object can be moved and drawn the same way.

Common mistakes

  • Writing class Dog : Animal: for a class, inheritance is private by default, and rex.eat() from main is refused. Write : public Animal.
  • Trying to use the base class's private members in the derived class: make them protected, or use public member functions.
  • Expecting a base-class pointer to call the derived version of a function: that needs virtual (next lesson).

Best practices

  • Use public inheritance only when the derived class truly is a kind of the base.
  • Keep data private where possible, and give derived classes protected functions instead.
  • Keep hierarchies shallow, since deep ones are hard to change.

Summary

Inheritance lets a derived class reuse and extend a base class. The base part is built first and destroyed last, protected members are open to derived classes, and inheritance should model "is a", while "has a" uses a member.

Quick check

1. Building a Car (derived from Vehicle) runs which constructor first?
2. Animal has a protected member name. Where can it be used?
3. Which relationship suits inheritance?

Key takeaways

  • A derived object contains a base part.
  • The base part is built first and destroyed last.
  • Inherit only for "is a"; use a member for "has a".

Practice problems for this lesson

My notes

Write down what you want to remember from this lesson. Notes are saved on this device as you type, and appear on your dashboard.