C++ Course
Inheritance
In Lesson 13 you met the idea: one of the four pillars of object-oriented programming is inheritance. It lets a new class reuse the members of a class that already exists, instead of writing them all over again. The class that is inherited from is the base class (also called the parent class). The class that inherits is the derived class (also called the child class). Write the shared behaviour once, inherit it everywhere you need it.
What Is Inheritance?
A dog eats and sleeps, and so does a cat. Instead of writing eat() and sleep() inside both classes, write them once in an Animal class and let Dog and Cat inherit them. The derived class gets everything the base class has β and can add its own members on top:
#include <iostream>
class Animal {
public:
void eat() { std::cout << "Eating..." << std::endl; }
void sleep() { std::cout << "Sleeping..." << std::endl; }
};
class Dog : public Animal {
public:
void bark() { std::cout << "Woof!" << std::endl; }
};
int main() {
Dog dog;
dog.eat();
dog.sleep();
dog.bark();
return 0;
}Eating... Sleeping... Woof!
The line class Dog : public Animal is the whole trick: the colon and the word public say that Dog inherits from Animal. A Dog object can call eat() and sleep() even though those functions were only written in Animal.
The is-a test: inheritance fits when you can say A Dog IS an Animal. When the sentence is A Car HAS an engine, that is not inheritance β it is composition, a member object inside the class.
The Syntax β public, protected, private Inheritance
The word after the colon chooses how the base class members arrive in the derived class. There are three forms, but in practice you will use public inheritance almost always β it is the only form that keeps the is-a relationship true:
| Inheritance | public members of the base become | protected members of the base become | private members of the base |
|---|---|---|---|
| public | public | protected | not accessible |
| protected | protected | protected | not accessible |
| private | private | private | not accessible |
Notice that private members of the base are never accessible to the derived class β no form of inheritance opens them. That is what protected is for: a member marked protected is private to the outside world, but the derived class can use it:
#include <iostream>
class Animal {
protected:
int legs = 4;
public:
void showLegs() { std::cout << "Legs: " << legs << std::endl; }
};
class Dog : public Animal {
public:
void run() { std::cout << "Running on " << legs << " legs." << std::endl; }
};
int main() {
Dog dog;
dog.run();
dog.showLegs();
return 0;
}Running on 4 legs. Legs: 4
The derived class reads legs directly, but code in main cannot write dog.legs β that would not compile, because protected is still closed to the outside.
Constructors and Destructors in Inheritance
When a derived object is created, the base constructor runs first, then the derived constructor. When the object dies, the order reverses: the derived destructor runs first, then the base destructor. Base first in, last out:
#include <iostream>
class Animal {
public:
Animal() { std::cout << "Animal constructed." << std::endl; }
~Animal() { std::cout << "Animal destroyed." << std::endl; }
};
class Dog : public Animal {
public:
Dog() { std::cout << "Dog constructed." << std::endl; }
~Dog() { std::cout << "Dog destroyed." << std::endl; }
};
int main() {
Dog dog;
return 0;
}Animal constructed. Dog constructed. Dog destroyed. Animal destroyed.
If the base constructor needs arguments, the derived constructor passes them with an initializer list: Dog(std::string n) : Animal(n) {}. The base is always built before the derived class adds its own part.
Overriding β A Child Can Replace a Parent's Function
A derived class can define its own version of a base class function. That is called overriding. For a derived object, the derived version wins:
#include <iostream>
class Animal {
public:
void speak() { std::cout << "Some sound." << std::endl; }
};
class Dog : public Animal {
public:
void speak() { std::cout << "Woof!" << std::endl; }
};
class Cat : public Animal {
public:
void speak() { std::cout << "Meow!" << std::endl; }
};
int main() {
Animal animal;
Dog dog;
Cat cat;
animal.speak();
dog.speak();
cat.speak();
return 0;
}Some sound. Woof! Meow!
Not yet polymorphism: without the virtual keyword, this choice is made at compile time. An Animal pointer to a Dog would still call Animal's speak(). Lessons 18 and 23 add virtual and make the choice happen at run time.
Types of Inheritance
Inheritance comes in several shapes. You will use single and hierarchical inheritance the most; multiple inheritance is possible in C++ but needs care, because two bases can both bring the same member (the diamond problem).
| Type | What it means | Example |
|---|---|---|
| Single | One base, one derived | Dog : Animal |
| Multilevel | A chain of classes | Animal β Mammal β Dog |
| Multiple | One class from two bases | FlyingCar : Car, Airplane |
| Hierarchical | One base, many derived | Animal β Dog, Cat, Bird |
| Hybrid | A mix of the above | A class using two or more forms |
Common Mistakes with Inheritance
| Mistake | What happens | Do this instead |
|---|---|---|
| Using inheritance for a has-a relationship | A Car is not an Engine β the hierarchy makes no sense | Use a member object (composition) |
| Expecting private base members to be inherited | Private members stay private β the derived class cannot see them | Use protected for members the child needs |
| Hiding a base function by accident | A derived function with the same name but a different signature hides all the base versions | Match the signature, or write using Base::func; |
| Deep inheritance chains | A β B β C β D β E is hard to follow and hard to change | Keep the hierarchy shallow; prefer composition |
| Forgetting the construction order | You expect the derived constructor to run first | Remember: base first in, last out |
Practice β Inheritance
Try these before moving on. Write each program, compile it, and read the output β the output is the lesson.
- Build the
Animalclass from this lesson (eat, sleep) and aDogclass that inherits from it, then add aCatclass that inherits fromAnimaland addsmeow(). - Add a protected member to the base class and use it in the derived class. Then try to use it from
mainand read the error message. - Write a multilevel chain:
VehicleβCarβSportsCar, each adding one function, and print the construction order. - Override
speak()in two derived classes and call it on each object. Then try calling it through a base-class pointer and note which version runs (Lesson 23 explains why).
What does inheritance let a class do?
In class Dog : public Animal, which class is the base class?
When a Dog object is created, which constructor runs first?
Fill in the blanks β type the missing word into the box.
The class that is inherited from is called the class.
The most common form of inheritance is written class Dog : Animal.
The class that inherits from another class is called the class.
Up Next
Polymorphism
One interface, many forms β see how the same function call can behave differently.
