Skip to content
Theory · Classes and OOP · lesson 7 of 13

Inheritance

A bird is an animal too: it has everything any animal has, plus something of its own. If Bird is written as a separate class, the animal's fields have to be repeated. Instead, Bird is declared as derived from Animal:

C++
#include <iostream>

struct Animal {
    int legs = 4;
};

struct Bird : public Animal {
    bool flies = true;
};

int main() {
    Bird b;
    b.legs = 2;
    std::cout << b.legs << ' ' << b.flies << '\n';  // 2 1
}

Base and derived classes

Here Animal is the base class, and Bird is the derived class. A Bird object contains a whole Animal object inside it, so b has both the field legs and its own field flies. The derived class inherits the fields and methods of the base class, but not its constructors. If Animal has a constructor Animal(int legs), the derived class calls it in its own initializer list: Bird() : Animal(2) {}.

The word public before Animal keeps the access: public fields and methods of the base stay public in the derived class. The private fields of the base class are in the object too, but the methods of the derived class cannot reach them. For fields that derived classes need but the rest of the code must not touch, there is the protected: label. Such a field of Animal can be changed by a method of Bird, but not by main.

References, pointers and copies

A derived object can go where a base one is expected: Bird& converts implicitly to Animal&, and Bird* to Animal*. So one function with a const Animal& parameter fits any class derived from Animal. Through such a reference or pointer, only the fields and methods of Animal are available. A field behind a pointer is reached with an arrow: ptr->legs means the same as (*ptr).legs.

A copy is a different story. Storing a derived object in a base-type variable creates a new Animal object and copies only the Animal part into it. This is object slicing: the field flies does not make it into the copy, and the copy lives apart from b.

C++
Bird b;
Animal& ref = b;
Animal copy = b;
b.legs = 2;
std::cout << ref.legs << ' ' << copy.legs << '\n';  // 2 4

ref denotes the object b itself and sees the new value, while copy keeps the old one. The line copy.flies does not compile: an Animal object has no such field.

Common mistake

The derived class is declared with class, and public is left out:

C++
class Animal {
public:
    int legs = 4;
};

class Bird : Animal {};

int main() {
    Bird b;
    return b.legs;  // ✗
}
TEXT
error: 'legs' is a private member of 'Animal'

With class, inheritance is private by default: the public fields of Animal become private in Bird. Write class Bird : public Animal. With struct, inheritance is public by default, but public is written there too, so nobody has to guess.