Intermediate 12 min

Inheritance Basics

Learn how to create derived classes that inherit properties and behaviors from base classes

Learn how to create hierarchies of related classes where derived classes inherit and extend functionality from base classes.

A Simple Example

#include <iostream>
#include <string>

class Animal {
protected:
    std::string name;
    int age;

public:
    Animal(std::string name, int age) : name{name}, age{age} {
        std::cout << "Animal constructor: " << name << "\n";
    }

    void eat() {
        std::cout << name << " is eating" << "\n";
    }

    void sleep() {
        std::cout << name << " is sleeping" << "\n";
    }

    void displayInfo() {
        std::cout << "Name: " << name << ", Age: " << age << "\n";
    }
};

class Dog : public Animal {
private:
    std::string breed;

public:
    Dog(std::string name, int age, std::string breed)
        : Animal{name, age}, breed{breed} {
        std::cout << "Dog constructor: " << name << "\n";
    }

    void bark() {
        std::cout << name << " says: Woof! Woof!" << "\n";
    }

    void displayBreed() {
        std::cout << name << " is a " << breed << "\n";
    }
};

class Cat : public Animal {
private:
    bool isIndoor;

public:
    Cat(std::string name, int age, bool indoor)
        : Animal{name, age}, isIndoor{indoor} {
        std::cout << "Cat constructor: " << name << "\n";
    }

    void meow() {
        std::cout << name << " says: Meow!" << "\n";
    }

    void displayLocation() {
        std::cout << name << " is " << (isIndoor ? "indoor" : "outdoor") << "\n";
    }
};

int main() {
    Dog dog{"Buddy", 3, "Golden Retriever"};
    dog.displayInfo();    // Inherited from Animal
    dog.eat();            // Inherited from Animal
    dog.bark();           // Dog's own method
    dog.displayBreed();

    std::cout << "\n";

    Cat cat{"Whiskers", 2, true};
    cat.displayInfo();    // Inherited from Animal
    cat.sleep();          // Inherited from Animal
    cat.meow();           // Cat's own method
    cat.displayLocation();

    return 0;
}

Breaking It Down

Base Class Declaration

  • What it does: The Animal class defines common properties (name, age) and behaviors (eat, sleep)
  • protected members: Accessible to derived classes but not to outside code
  • public methods: Interface that all animals share
  • Remember: Design the base class to contain what all derived classes have in common

Derived Class Syntax: class Dog : public Animal

  • The colon : indicates inheritance from Animal
  • public inheritance means public members stay public in Dog
  • Dog automatically gets all Animal members and methods
  • Remember: Use public inheritance for "is-a" relationships (Dog is-a Animal)

Constructor Initialization List

  • Derived constructor must call base constructor: Animal{name, age}
  • Base constructor runs first, then derived constructor
  • Base constructor initializes base class members
  • Remember: You cannot initialize base class members directly in derived constructor

Adding Specialized Behavior

  • Dog adds bark() method and breed data member
  • Cat adds meow() method and isIndoor data member
  • Each derived class keeps common functionality and adds its own
  • Remember: Inheritance promotes code reuse while allowing specialization

Why This Matters

  • Inheritance is about modeling real-world relationships in code. A Dog is an Animal, a Manager is an Employee, a SavingsAccount is a BankAccount.
  • Instead of duplicating common code, you inherit it from a base class and add specialized behavior. This makes your code more maintainable - fix a bug in the base class, and all derived classes benefit.
  • It's foundational for building extensible systems and implementing polymorphism.

Critical Insight

When you create a derived class object, C++ calls constructors from the top down - base class first, then derived class. When destroying, it's reverse - derived destructor first, then base. This ensures the base class part is ready before the derived class constructor runs:

class Base {
public:
    Base() { std::cout << "1. Base constructed\n"; }
    ~Base() { std::cout << "4. Base destroyed\n"; }
};

class Derived : public Base {
public:
    Derived() { std::cout << "2. Derived constructed\n"; }
    ~Derived() { std::cout << "3. Derived destroyed\n"; }
};

int main() {
    Derived d;  // Output: 1, 2 (construction)
    // When d goes out of scope: 3, 4 (destruction)
}

Think of it like building a house: you need the foundation (base) before the walls (derived).

Best Practices

Use public inheritance for "is-a" relationships: When Dog is-a Animal, use class Dog : public Animal. This is the most common form.

Make shared data protected, not public: Base class members that derived classes need should be protected so external code cannot access them directly.

Always call base constructor in initialization list: Derived constructors must initialize the base class using the initialization list, not in the body.

Design base classes for inheritance: Include a virtual destructor if your class will be used polymorphically.

Common Mistakes

Forgetting to call base constructor: Derived class constructors must explicitly call the base constructor in the initialization list.

Using private instead of protected: Private base members are not accessible in derived classes, even with inheritance.

Incorrect inheritance syntax: Must specify access level in inheritance, like class Dog : public Animal, not just class Dog : Animal.

Trying to initialize base members directly: You cannot assign to base class members in the derived constructor body - must use base constructor.

Debug Challenge

This Dog class has a bug in its constructor. Click the highlighted line to fix it:

1 #include <iostream>
2 #include <string>
3
4 class Animal {
5 protected:
6 std::string name;
7 public:
8 Animal(std::string n) : name{n} {}
9 };
10
11 class Dog : public Animal {
12 public:
13 Dog(std::string n) {
14 name = n;
15 }
16 };

Quick Quiz

  1. What order are constructors called when creating a derived class object?
Base first, then derived
Derived first, then base
Random order
  1. What access specifier should base class members use if derived classes need direct access?
protected
private
public
  1. What does a derived class inherit from its base class?
All members (but access depends on specifiers)
Only public members
Only methods, not data

Practice Playground

Time to try out what you just learned! Play with the example code below, experiment by making changes and running the code to deepen your understanding.

Lesson Progress

  • Fix This Code
  • Quick Quiz
  • Practice Playground - run once