Inheritance is an important part of C++ and the Object Oriented Paradigm. It further expands on the concept of Classes and Objects, and introduces the idea of Parent Classes and Child Classes, where the Child Classes “inherit” variables and functions from the Parent.
Inheritance introduces a higher degree of Abstraction, Flexibility and Re-usability that if used properly, can dramatically improve the quality of your code and save you alot of time amongst other benefits.
Note: The terms Parent Class and Base Class, and Child Class and Derived Class are interchangeable with each other.
Understanding Access Modifiers
Before we begin, let’s do a review of Access Modifiers in C++. These play an important role when we inherit from one Class to another, so knowing exactly what they do is key.
There are three Access Levels in C++, Private, Public and Protected. Access Levels are basically “Protection” levels, which state how much access is being allowed for a certain function/variable. Access modes are used in two different situations. When defining member variables and functions, and when inheriting from classes.
Private:
The default Access Mode for most situations, because it’s the most secure option. The “Private” Access Mode means that only members within that class can access each other. Any attempt by external code to access private variables/methods with the private keyword, will be restricted.
In easier words, a private method/variable can only be accessed within the Class in which it was declared. Even Child Classes cannot access the private members from the Parent. If a Child Class inherits from a Parent Class, only the Public and Protected members will be inherited.
For private variables, we often make “setters” or “getters”, which allow external code to modify/get the values of the variable in question. The difference being however, we get to limit/control how the user modifies that variable.
Public:
Public is an Access Mode setting where it basically “public” and accessible to anyone, inside or outside of the Class. Any variable can be accessed or modified and any function can be called.
Protected:
Protected is a rather special Access Mode used only during Inheritance of Classes. Sometimes we want our variables or methods to be private, but we want the Child Classes to be able to access them without making them public.
In such cases, we use the Protected Keyword on variables/functions in the Parent Class, which allows Child Classes to access them, while keeping them private for all other purposes.
Inheritance in C++
When inheriting from a Base Class, you need to specify the access level of the Inheritance you want. There are three different access levels of Inheritance, private (default), public and protected. The member variables and function that get inherited from the Base Class, depend on the type of Inheritance used.
The one thing common across all Inheritances, is that the private variables and functions never get inherited. However, what does change is the access level of the public and protected members inherited.
Private Inheritance
Private Inheritance is the default inheritance type, if you inherit without mentioning a type.
class Person { };
class Student : private Person {};
In this inheritance, all the public and protected members are inherited as private. Hence if a public variable called “name” was inherited from “Person” through private inheritance, it will be a private member in “Student”.
Besides the fact you won’t be able to access it externally, this also means that if another Class inherits from Student, the variable name will not be inherited again.
Public Inheritance
To use public Inheritance, simply use the public keyword when inheriting as shown below.
class Person { };
class Student : public Person {};
Public inheritance is probably the most commonly used one, where everything you inherit gets copied over with the same access level. Public members get inherited as public, and protected members get inherited as protected.
Protected Inheritance
Public Inheritance can be used by using the private keyword when inheriting as shown below.
class Person { };
class Student : protected Person {};
Protected Inheritance is there for the purpose where you want the inherited members to be private in nature (with regards to external access), but also want to allow other Classes to inherit from the Child Class.
In short, Protected Inheritance inherits all member variables and functions as protected.
Examples of Inheritance in C++
Let’s go through some actual examples of inheritance and C++, and discuss the code involved.
Example #1
In the below example, we use our “Student” and “Person” example. “Person” possess two variables, which we can expect every person to have, a “name” and an “age”. Now instead of making these variables in the Student Class as well, we can just inherit them from the Person Class.
The below example includes many other Class-related concepts, in order to give a proper real world example of what Classes look like. Notice how the access modes have been used, and how we used setters and getters.
#include <iostream>
using namespace std;
class Person {
public:
string getName() { return name; }
int getAge() { return age; }
protected:
string name;
int age;
};
class Student : public Person {
public:
Student(string name, int age, int roll, string dept) {
this->name = name;
this->age = age;
this->rollNo = roll;
this->department = dept;
}
void print() {
cout << "Name: " << name << " (" << age << ")\n";
cout << "Roll No: " << rollNo << endl;
cout << "Department: " << department << endl;
}
string getDepartment() { return department; }
int getRollNo() { return rollNo; }
private:
int rollNo;
string department;
};
int main() {
Student student1 = Student("Bob", 18, 204, "Business");
student1.print();
}
Name: Bob (18)
Roll No: 204
Department: Business
The main takeaway here with regards to inheritance is how we were able to access and modify the variables from the Parent class in the Child Class.
It may seem rather pointless to inherit just two variables (along with their getters and setters), but even this much has it’s uses when it comes to concepts like Upcasting and Downcasting. The real benefit of Inheritance kicks in when you are creating multiple Child Classes that have several variables and functions in common with each other.
Example# 2
Let’s take a look at another example with some different Classes involved.
This time we’ll try to be a bit more practical, and focusing on the inheritance of functions. Practically speaking, Inheritance’s greatest benefit is that if there are 5-6 Classes that have a few common functions, then we only need to write them once, instead of writing it again each time in each Class.
The below example shows an example with an Animal Class and a Dog Class. The Animal Class has functions like eat() and walk(), which can be found in all animals. Now any Class inheriting from Animal will automatically have these functions.
We have also added a variable called hunger, and allowed the functions to modify it’s value as they are called.
#include <iostream>
using namespace std;
class Animal {
public:
void walk() {
cout << "Walking..." << endl;
hunger = hunger + 1;
}
void eat() {
cout << "Eating..." << endl;
hunger = hunger - 5;
}
int getHunger() { return hunger; }
protected:
string species;
int age;
int hunger;
};
class Dog : public Animal {
public:
Dog(string brd, string sp, int age) {
species = sp;
breed = brd;
age = age;
hunger = 0;
}
private:
string breed;
};
int main() {
Dog doggy = Dog("Poodle", "Dog", 4);
doggy.walk();
doggy.walk();
doggy.walk();
doggy.walk();
doggy.walk();
doggy.walk();
cout << "Current Hunger: " << doggy.getHunger() << endl;
doggy.eat();
cout << "Current Hunger: " << doggy.getHunger() << endl;
}
Walking...
Walking...
Walking...
Walking...
Walking...
Walking...
Current Hunger: 6
Eating...
Current Hunger: 1
Now we can easily make 4-5 other Child Classes (e.g Cat, Monkey), and simply inherit from Animal. Thanks to inheritance we won’t have to re-write any of these functions!
Example# 3
In this example, we will re-do Example 1, with a slight difference. There is an important thing to keep in mind, that when a Child Object is created, the Constructor of the Parent is called. This is because every Child Object in a sense, also holds an Object of it’s Parent. That is the reasoning behind how it can access it’s variables and functions after all.
The problem is currently, in the first example the default constructor for the Parent is being called. What if we don’t want that to happen? What if we won’t to have some custom code run, so we want a specific Constructor of the Parent to be executed.
The solution to this, is to use the C++ Initializer List. Just like how we can initialize variables using it, we can also call the constructor for the parent. For a more in-depth look at Initializer Lists, refer to it’s tutorial.
#include <iostream>
using namespace std;
class Person {
public:
Person(string name, int age) {
cout << "Parent Constructor Called!" << endl;
this->name = name;
this->age = age;
}
string getName() { return name; }
int getAge() { return age; }
protected:
string name;
int age;
};
class Student : public Person {
public:
Student(string name, int age, int roll, string dept) : Person(name, age) {
this->rollNo = roll;
this->department = dept;
}
void print() {
cout << "Name: " << name << " (" << age << ")\n";
cout << "Roll No: " << rollNo << endl;
cout << "Department: " << department << endl;
}
string getDepartment() { return department; }
int getRollNo() { return rollNo; }
private:
int rollNo;
string department;
};
int main() {
Student student1 = Student("Bob", 18, 204, "Business");
student1.print();
}
Parent Constructor Called!
Name: Bob (18)
Roll No: 204
Department: Business
Types of Inheritance in C++
Let’s discuss some of the common types of Inheritance. For a more detailed tutorial on Types of Inheritance in C++, complete with proper examples check out our separate dedicated tutorial.
Simple Inheritance
Simple Inheritance is “simply” inheriting from a Parent to a Child Class like we were in the examples before. It’s a relationship that exists between just two Classes. As we have already discussed this in detail, let’s skip ahead to the others.
We typically draw the arrow pointing from the Child to the Parent, to sort of visualize the fact that the Child is inheriting from the parent. It makes more sense to say, “Child inherits from Parent”, rather than say “Parent inherits to Child”.
Multilevel Inheritance
Multilevel inheritance is also very basic, and just an extension of Simple Inheritance, occurring when there is a chain of Inheritance between 3 or more Classes.
Let’s take a look at a short example on multilevel inheritance, showing the relationship between the three Classes.
class Animal { };
class Mammal : Animal { };
class Human : Mammal { };
The Animal has several sub-classes like Mammals, Reptiles, Birds etc. Likewise each of these sub-classes has hundreds of sub-classes, representing each animal species.
Multiple Inheritance
Multiple Inheritance is the concept of inheriting more than just one Class. Basically having more than one Parent Class.
Let’s take a look at a short example on multiple inheritance, showing the relationship between the three Classes.
class RangedUnit { };
class MeleeUnit { };
class AxeMan : public RangedUnit, public MeleeUnit { };
Often in games, while there are Ranged Units, and also Melee units, there are some that are a combination of both. The above example demonstrates this.
Note: This is a feature only available in some languages.
Hierarchical Inheritance
Hierarchical Inheritance is the concept of having multiple Classes inherit from the same Class, basically creating the concept of sibling Classes.
Let’s take a look at a short example on hierarchical inheritance, showing the relationship between the three Classes.
class MeleeUnit {};
class SpearMan : MeleeUnit {};
class SwordMan : MeleeUnit {};
A very simple example showing that SpearMan and SwordMan both inherit from MeleeUnit. The sibling relationship described in the example above actually does in handy with concepts like Upcasting and Downcasting.
There are one or two other types as well, which are just extensions or mixtures of the above mentioned ones. Honestly though you don’t need to focus on this too much. As long you as inherit from the right Classes, and write good, re-usable code, you are good to go.
Bonus Section: Inheritance in C++ Structs
As a slight bonus, let’s take a look at an example which shows Inheritance in Structs! It’s exactly the same as a Class, with just 2 minor differences.
First, by default all the member variables in a struct are public by default. Secondly, the default inheritance type is public by default as well.
(Keep in mind, C++ Structs are different from C structs. C++ Structs are also technically objects, hence they have alot of OOP features)
#include <iostream>
using namespace std;
struct Person {
string name;
int age;
char gender;
void print() {
cout << age << " - ";
cout << name << " - ";
cout << gender << endl;
}
};
struct Student : Person {
int RollNo;
string department;
};
int main() {
Student s1 = {"Bob", 15, 'M', 146, "IT"};
s1.print();
}
This marks the end of the C++ Inheritance Tutorial. Any suggestions or contributions are more than welcome. Questions regarding the tutorial content can be asked in the comments section below.