🧱 Section 3 · OOP 🟡 Intermediate MODULE 12

Inheritance — Base & Derived Classes

⏱️ 28 min
📖 Theory + Code
🧩 5 Quiz Questions
🏗️ 1 Challenge
Your progress in Section 350%
🎯 What you'll learn: What problem inheritance solves, the base-class/derived-class syntax (class Dog : public Animal), what a derived class actually inherits, how constructor chaining works, and what protected access is for.

What Problem Does Inheritance Solve?

Imagine you're modelling animals in a program: a Dog and a Cat both have a name and an age, and both can eat() and sleep(). Without inheritance, you'd copy-paste that code into every animal class — and if you ever needed to fix a bug in eat(), you'd have to fix it everywhere.

Inheritance lets one class (the derived class) automatically reuse the member variables and member functions of another class (the base class), and then add or specialize what makes it unique. It models an "is-a" relationship: a Dog is an Animal, a Cat is an Animal.

🧬
"is-a" vs "has-a"
Use inheritance for a true "is-a" relationship (a Dog is an Animal). If the relationship is really "has-a" (a Car has an Engine), you should make Engine a member variable of Car instead — that's called composition, not inheritance.
🏛️
Base Class
The general class being extended, e.g. Animal. Also called the "parent" or "superclass."
🐕
Derived Class
The specialized class that inherits from a base class, e.g. Dog. Also called the "child" or "subclass."
♻️
Code Reuse
Shared behaviour is written once in the base class, not duplicated in every derived class.
🔗
"is-a" Relationship
Inheritance should model a genuine specialization, not just convenient code sharing.

Base & Derived Class Syntax

To derive a new class, write a colon after the class name followed by an access level (almost always public) and the base class name: class Dog : public Animal. Every Dog object now automatically has everything a plain Animal has, plus whatever Dog adds.

animal_base.cpp
C++
class Animal {
protected:
    string name;
    int age;

public:
    Animal(string n, int a) {
        name = n;
        age  = a;
    }

    void eat() {
        cout << name << " is eating." << endl;
    }
};

// Dog "is-a" Animal — inherits name, age, eat()
class Dog : public Animal {
public:
    Dog(string n, int a) : Animal(n, a) {}

    void bark() {
        cout << name << " says: Woof!" << endl;  // name is inherited
    }
};

What Gets Inherited — and protected Access

A derived class inherits all member variables and member functions of its base class (except constructors and destructors, which have their own rules). But inherited does not always mean directly accessible — access still follows the specifiers:

1
public members
Inherited and remain accessible from anywhere the derived object is visible — including from outside the class.
2
protected members
Inherited and accessible inside the derived class's own member functions — but still hidden from code outside the class hierarchy.
3
private members
Inherited in the sense that they exist in memory, but the derived class's own code cannot directly access them — only the base class's methods can.
Why Animal used protected, not private
In the example above, name and age are protected specifically so that Dog::bark() can read name directly. If they were private, Dog would need to go through a public getter on Animal instead.

Constructor Chaining

A derived class doesn't automatically know how to initialize the base class's members — you must explicitly call a base class constructor, using an initializer list in the derived constructor. The base constructor always finishes running before the derived constructor's own body executes.

constructor_chaining.cpp
C++
class Cat : public Animal {
public:
    // ": Animal(n, a)" calls the Animal constructor FIRST
    Cat(string n, int a) : Animal(n, a) {
        // this body runs AFTER Animal's constructor has finished
    }

    void meow() {
        cout << name << " says: Meow!" << endl;
    }
};
⚠️
If you don't chain to a matching base constructor, it won't compile
If Animal has no default (no-argument) constructor, and Cat's constructor doesn't explicitly call Animal(n, a) in its initializer list, the compiler has no way to build the Animal part of the object — you'll get a compile error.

Complete Worked Example — Animal, Dog & Cat

Putting it all together: one base class, two derived classes, each reusing shared behaviour while adding their own.

animal_hierarchy.cpp
C++
#include <iostream>
#include <string>
using namespace std;

class Animal {
protected:
    string name;
    int age;

public:
    Animal(string n, int a) {
        name = n;
        age  = a;
    }

    void eat() {
        cout << name << " is eating." << endl;
    }

    void sleep() {
        cout << name << " is sleeping." << endl;
    }
};

class Dog : public Animal {
public:
    Dog(string n, int a) : Animal(n, a) {}

    void bark() {
        cout << name << " says: Woof!" << endl;
    }
};

class Cat : public Animal {
public:
    Cat(string n, int a) : Animal(n, a) {}

    void meow() {
        cout << name << " says: Meow!" << endl;
    }
};

int main() {
    Dog d("Rex", 3);
    Cat c("Whiskers", 2);

    d.eat();    // inherited from Animal
    d.bark();   // defined in Dog

    c.sleep();  // inherited from Animal
    c.meow();   // defined in Cat

    return 0;
}

Output:

Console Output
OUTPUT
Rex is eating.
Rex says: Woof!
Whiskers is sleeping.
Whiskers says: Meow!

Lesson Summary

Inheritance lets a derived class reuse a base class's members, modelling an "is-a" relationship.
Syntax: class Dog : public Animal { ... };
protected members are visible to derived classes but hidden from outside code — a middle ground between public and private.
Constructor chaining — a derived constructor explicitly calls a base constructor in its initializer list, e.g. Dog(n, a) : Animal(n, a) {}.
The base class's constructor always finishes running before the derived class's constructor body executes.
🧩 Knowledge Check — Lesson 12
Answer all 5 questions to test your understanding. Instant feedback on every answer.
1. What kind of relationship does inheritance model?
2. In class Dog : public Animal, which class is the derived class?
3. In a publicly-derived class, how are the base class's protected members treated?
4. When a Dog object is created, which constructor runs first?
5. How does a derived class call a specific base class constructor?
💪
Coding Challenge — Lesson 12
Apply what you learned · Intermediate Level

Now it's your turn to extend a class hierarchy. Complete the challenge below in any C++ compiler or online IDE.

Challenge: Add a Bird class 🐦

Using the Animal base class from Section 5 (with protected name and age, and public eat()/sleep()), create a new derived class Bird : public Animal that:

1. Has a constructor that chains to Animal's constructor.
2. Adds a new method fly() that prints "<name> is flying!".
3. In main(), create a Bird object and call eat(), sleep(), and fly() on it.
💡 Show hints if you're stuck
  • Header: class Bird : public Animal {
  • Constructor: Bird(string n, int a) : Animal(n, a) {}
  • fly() can use name directly since it's protected, not private
  • You don't need to rewrite eat() or sleep() — they come for free through inheritance
Finished this lesson?
Mark it complete to track your progress.
🎉

Lesson 12 Complete!

You can now build class hierarchies with inheritance. Next: what happens when derived classes need to behave differently through a base pointer — polymorphism.

Module 12 of 26 Section 3 — Object-Oriented Programming