Home

 › 

Articles

 › 

Inheritance in C++ Explained, With Examples

Inheritance in C++

Inheritance in C++ Explained, With Examples

As an object-oriented programming language, C++ frequently relies on the implementation of inheritance. This feature allows you to modify and reuse attributes and other characteristics of a class, as well as cut down on the amount of code you need. Read on to find out exactly what inheritance is and the types of inheritance in C++ you can use.

What is Inheritance?

Much in the way that we can “inherit” certain characteristics from our parents, in C++, classes can inherit members from another class. In this way, the class whose members are inherited is defined as the base or parent class, and the class that inherits these features is known as the derived class, subclass, or child class. Since this allows for members of the parent class to be reused, these members don’t need to be redefined. Therefore, you can save time implementing unnecessary code.

There are similarities with the friend function and friend class, since these allow functions and classes to access the members of other classes. However, friend allows access to private members, whereas inheritance doesn’t.

What are the Types of Inheritance in C++?

There are 5 types of inheritance in C++. These are:

  • Single Inheritance
  • Multilevel Inheritance
  • Multiple Inheritance
  • Hybrid Inheritance
  • Hierarchical Inheritance

Let’s take a look at each of these.

Single Inheritance

The simplest method of inheritance is where one class inherits the members of one other class. This can be shown with the following code:

#include <iostream>


class BaseClass {
public:
  int x;
};

class DerivedClass : public BaseClass{
public:
  int y;
};

int main() {
  DerivedClass obj;
  obj.x = 10
  obj.y = 20

  std::cout << "Base class member variable x = " <<obj.x << std::endl;
  std::cout << "Derived class member variable y = " << obk.y << std::endl;
  return 0;
}

Here, we’ve defined the base class as “BaseClass”, with member “x” that has public access. The derived class is defined as “DerivedClass”, which publicly inherits from “BaseClass”. The derived class itself has a public member called “y”. We create an instance of the derived class called “DerivedClass obj”, and set the x and y values. Using this object, we access the member “x” from the parent class, and the x and y values are printed to the console as shown in the screenshot.

Single Inheritance shown in an example.

Inheriting private members

It’s worth noting that the derived class could inherit all the members of the parent class because they have public access. However, if members are declared private, then these cannot be directly inherited. A way around this is if certain functions that act on these members are inherited. In this way, you can indirectly access these members. Take the following example:

class Base{
private:
  int a;

public:
  Base(int a) a(a) {}

  int getA() const {
    return a;
  }
};

class Derived : public Base {
public:
  Derived(int a): Base(A) {}
};

int main() {
    Derived d(5);
    std::cout << "Derived object's value: " << d.getA()<< std::endl;
    return 0;
}

Here, we’ve defined a parent class as “Base” and a derived class as “Derived”. The member “a” of the parent class is private, so not directly accessible by the derived class. But, we have a constructor in the base class which takes the integer argument of “a” and sets the private member “a”. The derived class has a constructor itself, “Derived(int a): Base (a) {}” which takes the integer argument “a” and passes it to the constructor of the base class. Because the “getA()” function has been inherited, so indirect access to the member “a” of the parent class is achieved.

Using the “main” function, we take an instance “d” of the derived class and define it with an argument of 5. The “getA()” function is called on this instance, and the output is printed. This is shown in the screenshot.

How to inherit private members, shown in an example.

Private vs. protected classes

It would be worthwhile at this stage to distinguish between private and protected classes. While private class members can only be accessed indirectly by derived classes, protected class members can be fully accessed by a derived class. But they can only be accessed within this class hierarchy, and not outside of it (this would be public access).

Method-only inheritance

These examples have also shown field inheritance, where the field “a” has been inherited. But you can also have method-only inheritance, where a method is used to define the behavior of the class. An example of this is shown below:

#inlude <iostream>

class Base {
public:
  virtual void bar() {
     std::cout << "Base::bar()" << std::endl;
  }
};

class Derived : public Base {
public:
  virtual voide bar() {
     std::cout << "Derived::bar()" << std::endl;
  }
};

int main() {
    Base* b = new Derived();
    b->bar(); // outputs "Derived::bar()"
    delete b;
    return 0;
}

Like before, we have a parent class “Base” and a derived class “Derived’. “Base” has a virtual method “bar()”. This is called virtual since it has no implementation in the parent class, and can be overridden by the derived class. The implementation if “bar()” is provided in the derived class definition. We can see that a pointer “b” is created within the “main()” function, and initialized with the object “Derived”. “Derived::bar()” overrides “Base::bar()”, since it’s a virtual function. The implementation within the derived class is called, which prints the output “Derived::bar()” as seen in the screenshot.

An example showing method-only inheritance.

Multilevel Inheritance

There are many cases where you may want to create a derived class from a class that has already been derived from a parent class. This is known as multilevel inheritance. As far as the types of inheritance in C++ go, this one is fairly intuitive. One such example is when you’re working with vehicle types. In this situation, you may have a parent class of “Vehicles” which defines certain methods and parameters universal to the vehicles you’re working with, such as cars and motorbikes. These could both be derived classes from this parent class, with their own specific properties. But since you may have particular types of these, you could then create derived classes like “PerformanceCar” which would then have their own applicable properties.

We can illustrate how this works with the following code:

#include <iostream>
#include <string>

class Vehicle {
public:
  std::string type;
  std::string color;
};

class Car : public Vehicle {
public:
  std::string model;
  int year;
};

class ElectricCar : public Car {
public:
  int batteryCapacity;
};

int main() {
    ElectricCar tesla;
    tesla.type = "Electric car";
    tesla.color = "Red";
    tesla.model = "Model S";
    tesla.year = 2021;
    tesla.batteryCapacity = 100;

    std::cout << "Type:" << tesla.type << std::endl;
    std::cout << "Color:" << tesla.color << std::endl;
    std::cout << "Model:" << tesla.model << std::endl;
    std::cout << "Year:" << tesla.year << std::endl;
    std::cout << "Battery Capacity:" << tesla.batteryCapacity << std::endl;

    return 0;
}

In this example, we have the “Vehicle” base class, the derived class “Car”, and a further derived class called “ElectricCar”. The “Vehicle” class has the “type” and “color” members, the “Car” class has members “model” and integer variable “year”, and the “ElectricCar” class has the integer member variable “batteryCapacity”. The main function creates an instance of the “ElectricCar” class, setting all of its inherited member variables with specific values. These variables are then printed to the console.

Multilevel Inheritance implemented in an example, together with its output.

Multiple Inheritance

Just like we can have a class derived from an already derived class, we can have a class that’s derived from more than one base class. We can demonstrate this by continuing with our car analogy:

#include <iostream>
#include <string>

class Vehicle {
public:
  std::string type;
  std::string color;
};

class ElectricEngine {
public:
  int batteryCapacity;
};

class SportsCar {
public:
  int topSpeed;
};

class ElectricSportsCar : public Vehicle, public ElectricEngine, public SportsCar {
public:
  std::string model;
  int year;
};

int main() {
    ElectricSportsCar tesla;
    tesla.type = "Electric car";
    tesla.color = "Red";
    tesla.model = "Roadster";
    tesla.year = 2022;
    tesla.batteryCapacity = 200;
    tesla.topSpeed = 250;

    std::cout << "Type:" << tesla.type << std::endl;
    std::cout << "Color:" << tesla.color << std::endl;
    std::cout << "Model:" << tesla.model << std::endl;
    std::cout << "Year:" << tesla.year << std::endl;
    std::cout << "Battery Capacity:" << tesla.batteryCapacity << "kWh" << std::endl;
    std::cout << "Top Speed:" << tesla.topSpeed << "mph" << << std::endl;

    return 0;
}

We have three classes here, “Vehicle”, “ElectricEngine” and “SportsCar”. These are all base classes, and have their properties inherited by the derived class “ElectricSportsCar”. As before, each of the parent classes has its own variables. An instance of “ElectricSportsCar” is created, values are assigned to its properties and these are then printed to the console.

An example of multiple inheritance.

Hierarchical Inheritance

We’re getting to the end of the different types of inheritance in C++. This is where the situation is a bit more nuanced. Although multilevel inheritance technically creates a hierarchy, this is different to what is known as hierarchical inheritance. If you’re creating multiple derived classes from one parent class, this is known as hierarchical inheritance. This is useful when you need to create related classes from a parent class, but each with its own properties. The code below shows this example.

class Vehicle {
public:
  std::string type;
  std::string color;
};

class Car : public Vehicle {
public:
  std:: string model;
  int year;
};

class Truck : public Vehicle {
public:
  int capacity;
};

Again, we have the “Vehicle” parent class, and both the “Car” and “Truck” classes are derived from it. Both of these classes inherit the “type” and color” variables, but add their own properties as well. Namely, “model” and “year” for the “Car” class and “capacity” for the “Truck” class. In the first screenshot, we can see the code implemented with the “main()” function, with an instance of each class created and its attributes set. The second screenshot shows the output in the console.

Hierarchical Inheritance implemented in a class.

The output of the example above.

Hybrid Inheritance

The situation gets a little more complex when it comes to hybrid inheritance. This is where different types of inheritance in C++ are combined together in one class hierarchy. While this can get complex, sometimes it’s necessary for the operations you need to perform. Consider the following situation:

#include <iostream>
#include <string>

class Vehicle {
public:
  std::string type;
  std:: string color;
};

class Engine {
public:
  int horsepower;
};

class Car: public Vehicle, public Engine {
public:
  std::string model;
  int year;
};

class ElectricCar : public Car {
public:
  int batteryCapacity;
};

in main() {
   ElectricCar tesla;
   tesla.type = "Electric car";
   tesla.color = "Red";
   tesla.model = "Model S";
   tesla.horsepower = 300;
   tesla.year = 2021;
   tesla.batteryCapacity = 100;
   tesla.type = "Electric car";

   std::cout << "Type:" << tesla.type << std::endl;
   std::cout << "Color:" << tesla.color << std::endl;
   std::cout << "Horsepower:" << tesla.horsepower << std::endl;
   std::cout << "Model:" << tesla.model << std::endl;
   std::cout << "Year:" << tesla.year << std::endl;
   std::cout << "Battery Capacity:" << tesla.batteryCapacity << std::endl;

   return 0;
}

As before, we have the “Vehicle” parent class, but also the “Engine” parent class. We have an example of multiple inheritance, where the “Car” class is derived from both the “Vehicle” and “Engine” classes. The “ElectricCar” class is then derived from the “Car” class, which is an example of multilevel inheritance, as this is a more specialized type of car. Therefore, we have a scenario where hybrid inheritance is taking place. As such, hybrid inheritance can be useful to help simplify and understand complex relationships, as well as make the code easier to maintain.

The first image illustrates the code implementation, where we’ve created an instance of the “ElectricCar” class with its attribute set from all of its parent classes. The printed output is shown in the second image.

Hybrid Inheritance implemented in a class.

The output of the above example.

A Note on Ambiguity

A very common problem that can arise when dealing with multiple classes is the issue of ambiguity. This is where you have you have identical member variables or functions in two or more classes. The compiler can then run into errors, as it cannot decide which member to use for the operation you’re trying to run. Consider the following code:

#include <iostream>

class A {
public:
  void foo() {std::cout << "A:foo()" << std::endl;}
};

class B {
public:
  void foo() {std::cout <<"B::foo()" << std::endl;}
};

class C : public A, public B {
public:
};

int main() {
    C c;
    c.foo(); // Compiler error: ambiguous call to foo() from A and B
    return 0;
}

Here, we have a function named “foo()” in both class “A” and class “B”. Since class “C” has inherited from both of these classes, an error occurs during compilation. This can be resolved in a few different ways:

  • Renaming the conflicting function or variable in either the parent or derived class to avoid confusion.
  • Using the scope resolution operator (::) to specify the class containing the desired member function.
  • Virtual inheritance works on a similar notion to the previously mentioned virtual function. This can allow a derived class to inherit from parent classes without duplicating the base class that these parents share.
  • Overriding the conflicting function by redefining the function in the derived class with a specialized implementation.
An ambiguity error illustrated

.

Wrapping Up

There are 5 main types of inheritance in C++ you can make use of, each with its own specific use cases. While single inheritance may be suitable for relatively simple operations, when working with complex objects and relationships, other types such as multiple, multilevel, hierarchical, and hybrid inheritance may be more appropriate. These can be useful to make the code more intuitive and easier to maintain, as well as better representing the relationship between classes.

Frequently Asked Questions

What are parent classes and derived classes?

A parent class, also known as a base class, is the class inherited from. On the other hand, a derived class, subclass or child class inherits properties and attributes from the parent class.

What is inheritance in C++?

Inheritance is a process that enables you to create a derived class from a parent or base class, which inherits properties and member functions from the parent class. This can be useful to represent complicated relationships and reduce the need to repeat code implementation.

What are the different kinds of inheritance in C++?

There are 5 main kinds of inheritance in C++ – single, multiple, multilevel, hierarchical and hybrid. Single and multiple refer to a single class being derived from one or more than one base classes respectively. Multilevel inheritances means when a class is derived from a derived class. Hierarchical inheritance refers to when multiple classes are derived from one base class, and hybrid inheritance means a mix of these other types is used.

How do you implement inheritance in C++?

To make a class inherit from a parent class, you use a colon (:), followed by the access specifier (either public or protected in this case) and the base class name.

 

What are public, protected and private members?

Public members are completely visible and accessible from anywhere within a program, and can be accessed by any function within or outside of the class. Protected members can be accessed by derived classes, so can be inherited. Private members cannot be accessed by any function outside of the class, and are invisible to derived classes. However, private members can be indirectly if a public function that acts on them is inherited.

What's the difference betweeen public, private and protected inheritance?

Public inheritance is where all the public members of the base class become public members of the derived class, and similarly with protected and private members. Protected inheritance is where both public and protected members are inherited, but private members remain inaccessible. Private inheritance means public and protected members become private members of the derived class, and, as always, private members remain invisible.

How do you resolve ambiguity in inheritance?

You can resolve ambiguity by using the scope resolution generator, using virtual inheritance or by renaming or redefining the conflicting functions.

To top