Home Resource Centre Inheritance In C++ & Its 5 Types Explained With Multiple Examples

Inheritance In C++ & Its 5 Types Explained With Multiple Examples

In the world of programming, building efficient and maintainable software is a constant pursuit. In this endeavour, one of the most fundamental and powerful concepts is inheritance. It is a cornerstone of object-oriented programming (OOP) concepts that empower developers to create new classes that inherit attributes and behaviours from existing ones. The mechanism of inheritance in C++ programming fosters code reusability and lays the foundation for structuring and organizing code in a way that mirrors real-world relationships.

In this article, we will explore what inheritance in C++ is, how it works, its types and practical use cases with some real-life examples.

What Is Inheritance In C++?

Inheritance in C++ language is a core concept of object-oriented programming (OOP) that allows you to create new classes (derived classes or child classes) based on existing classes (base classes or superclasses). It enables a subclass to inherit all the properties of the base class and add some new features to itself.

Let’s understand it clearly with the help of a real-life example:

To begin with, let's assume that inheritance does not exist. Then, consider the term animal, which consists of all types of animals. Here, you will have to create classes for all different types of animals, like Dogs, Cats, and Tigers. The methods speed(), eating(), and running() will be the same for all three classes. If we avoid inheritance while creating these classes, then we have to write all these methods for each class as shown below:

You can see that this process leads to replication of the same code 3 times. That is, we created 3 individual/ independent classes, each of which has a repetition of the same methods. This increases the redundancy in code and makes it prone to error.

In contrast, if inheritance existed, then we could avoid this kind of situation. How? Well, you could create a parent class called Animal with the three methods. You could then inherit the three classes (Dogs, Cats, and Tigers) from the Animal class. This reduces unnecessary repetitions, making the code much more meaningful (refer to the diagram below).

This example showcases how inheritance simplifies code development by allowing new classes to inherit properties and behaviours from existing ones, promoting code reuse and maintainability.

What Are Child And Parent Classes?

Inheritance introduces the concepts of the child (derived) and parent (base) classes. That is:

  • child class (derived) - the class that inherits from another class
  • parent class (base) - the class being inherited from

A child class inherits properties and behaviours from a parent class, allowing you to create specialized classes while reusing common attributes and functionalities. Think of it as a family tree where the characteristics are passed down from parents to children. In the previously explained example, the Dog, Cat, and Tiger class (child) inherits the attributes and methods from the Animal class (parent).

The Is-A relationship

Inheritance in C++ represents an is-a relationship between the child and parent classes. This means that an object of a child class is also an object of the parent class. For instance, if the Car class is derived from the Vehicle class, you can say that a car is-a vehicle, or if Cat is derived from Animal, you can also say that a cat is-a(an) animal.

Syntax And Structure Of Inheritance In C++

The structure of inheritance in C++ contains a child class, which inherits the attributes and methods, and a parent class. The syntax for defining a parent and child class in all types of inheritance in C++ is explained below.

Inheritance In C++ Syntax:

class ParentClassName {
// parent class definition
};

class ChildClassName : visibility_mode ParentClassName {
// child class definition
};

Here,

  • class: It is the keyword for creating a new class.
  • ParentClassName: It is the name of the base class or parent class.
  • ChildClassName: It is the name of the derived class or child class.
  • Visibility_mode: It is the access specifier that determines how inherited members are visible in the derived class (public, protected, or private).

Note:

  • If neither visibility mode is specified, it takes private as the default mode.
  • Private members of the base class never get inherited by the child class.
  • If the public members of the base class are privately inherited by the child class, then they become the private members of the child class. Thus, the public members of the base class are only accessible by the member functions of the child class, not by the object of the child class.

Implementing Inheritance In C++

When implementing inheritance in C++ programs, you must clearly indicate which class is inheriting from the other class. The syntax to be used when creating a child class that inherits the properties of the base class is given below.

Syntax For Implementing Inheritance In C++:

class <derived_class_name> : <access_specifier> <base_class_name>
{
// body of the child class - class definition
}

Here, 

  • The class keyword indicates that we are creating a new class and the colon symbol (:) is the indicator of inheritance in C++.
  • base_class_name is the name of the base class.
  • derived_class_name is the name of the class that will inherit the properties of a base class.
  • access_specifier defines the visibility mode through which the derived class has been created (public, private, or protected mode).

In a later section, we’ll discuss public, private, and protected modes of inheritance in C++ detail. But before that, let's understand how to implement inheritance in C++ with example program below.

Code Example:

Output:

Animal makes a sound
Dog barks

Explanation:

In this simple C++ program, a class Dog is derived from the class Animal, and the speak() function is overridden in Dog to provide a specialized behaviour.

  1. We begin by including the <iostream> header file for input/ output operations and namespace std to use its classes without calling it.
  2. As mentioned in the code comments, we create a parent or base class Animal and define the speak() function, which prints a statement using the cout command. The use of a public access modifier makes the function publicly accessible.
  3. Then, we create another class, Dog, which inherits the Animal class with the public access modifier. This is the child class.
  4. Inside the Dog class, we use the public access modifier to create the speak() function that overrides the function from the base class. 
  5. In the main() function, we create two objects, animal and dog, of the Animal and Dog classes, respectively.
  6. We then use the dot operator (>) and class objects to call the speak() methods from both classes. 
  7. The first call invokes the Base class function, and the second call invokes the method from the derived class. 
  8. The program finally terminates with a return 0 statement indicating successful execution without any errors.

Importance Of Inheritance In C++

Inheritance is one of the fundamental features of object-oriented programming (OOP) and is especially important in C++. It allows you to create new classes based on existing classes, inheriting their attributes and behaviours. Here are some of the key reasons why inheritance in C++ is important:

  • Polymorphic Containers: Inheritance in C++, combined with polymorphism, enables you to create containers (e.g., arrays or collections) that can hold objects of different derived classes but still operate on them using common base class interfaces. This is valuable for creating data structures and algorithms that work with heterogeneous data.
  • Method Overriding: Inheritance in C++ allows derived classes to provide their own implementations of base class member functions through a mechanism called method overriding. This is particularly useful when you want to customize the behaviour of a derived class while maintaining a consistent interface defined in the base class.
  • Conceptual Modeling: Inheritance in C++ allows you to model real-world relationships between objects. For example, in a system for modelling animals, you can have a base class, Animal, and derived classes like Dog, Cat, and Bird, which accurately represent the inheritance hierarchy in the real world.
  • Encapsulation: Inheritance in C++ supports the principle of encapsulation, which involves bundling data and methods into a single unit (class). By inheriting from base classes, you can access and manipulate the data and methods of the base class within the derived class, following the access control rules defined in C++.
  • Behavioural Classification: Inheritance in C++ allows you to classify objects based on their behaviours or characteristics. For example, you can have a base class Vehicle and derived classes like Car and Motorcycle, which share common characteristics and behaviours specific to vehicles.
  • Template for Design Patterns: Many design patterns, such as the Factory, Singleton, and Strategy patterns, rely on inheritance to implement their solutions. Inheritance in C++ provides a foundation for creating and using these design patterns effectively.
  • Better Code Organization: The concept of inheritance in C++ helps in organizing and structuring your code in a more logical and systematic manner, making it easier to understand and navigate.
  • Framework and Library Design: Inheritance in C++ programs is crucial when designing frameworks and libraries. Frameworks often provide base classes with defined behaviours, allowing users to create derived classes tailored to their specific requirements. This approach encourages standardization and reuse in software development.

Check this out- Boosting Career Opportunities For Engineers Through E-School Competitions

Types Of Inheritance In C++

There are five different types of inheritance in C++ based on how the derived class inherits the base class features. These five types are as follows:

  1. Single inheritance
  2. Multilevel inheritance
  3. Multiple inheritance
  4. Hierarchical inheritance
  5. Hybrid inheritance

In this section, we will discuss all these types in greater detail with the help of code examples. 

Single Inheritance in C++

In single inheritance, a derived class inherits from a single base class, i.e., a child class inherits from a single parent class. As shown in the diagram above, class B (which is the subclass) inherits the properties of class A, which is the only parent class.

For example, consider Vehicle as a base class and a Car as the child class inherited only from it. It is also referred to as single level inheritance. 

Syntax For Single Inheritance In C++:

class BaseClass {
// Body of the class
};

class DerivedClass : access_modifier BaseClass {
// Body of the class
};

Here,

  • BaseClass and DerivedClass are the names of the base/ parent and derived/child classes, respectively.
  • The classes are created using the class keyword.
  • The access_modifier is the specifier that determines the mode of visibility of the inherited members in the derived class.

Let’s understand single inheritance in C++ with an example program.

Code Example:

Output:

The product of x & y is: 42

Explanation

We begin the C++ code example by including essential header files and the namespace std to use its classes without the need to call it every time.

  1. Then, we create a class P with two integer variables/ data members, x and y, that are initialized with the values 6 and 7, respectively. 
  2. We also define a product() function inside the P class, which calculates and returns the product of x and y, stored in variable z. The use of the public keyword makes the function publicly accessible to the inherited class objects.
  3. Next, we create another class, C, which inherits the P class with the private access modifier. Inside the class-
    • We define a display() function, which further calls the product() function whose result is stored in the ans variable, and it prints a phrase using the cout command
    • Also, we use the keyword public inside the class to define this function.
  4. Inside the main() function, we create an object res of the derived class C.
  5. Then, using the dot operator and the derived class object, we call the display() method, which invokes the product() function.
  6. The product of x and y gets stored in the ans variable, and the output is printed to the console.

Multiple Inheritance in C++

In multiple inheritance, a subclass inherits from multiple base classes, i.e., a child class inherits from more than one parent class. For example, say there are two base classes, Animal and FlyingObject. The former includes all types of animals, and the latter includes all types of flying objects. Then, a Bird class can be said to inherit from both Animal and FlyingObject classes.

Syntax For Mulitple Inheritance In C++:

class B1 {
// Base class members
};
class B2 {
// Base class members
};
class DerivedClass : access_modifier B1, access_modifier B2 {
// Derived class members
};

Here,

  • The class keyword indicates the creation of a new class.
  • B1 and B2 are the names for base classes or parent classes.
  • DerivedClass is the name of the derived class or child class. Note that we use the comma operator to separate the two base classes for the derived class.
  • The access_modifier determines how inherited members are visible in the derived class.

Let’s look at an example showcasing the implementation of multiple inheritance in C++. 

Code Example:

Output:

Eagle is an animal.
Eagle can fly in the air.

Explanation

In the sample C++ program-

  1. We first include the <iostream> header file and the namespace std and then create a class called Animal. Inside the class-
    • We define the member function animal(), which takes a string as input and displays it using the cout command.
    • The use of a public access modifier makes the function publicly accessible to the inherited class objects.
  2. Next, we create another class Aerial, with a public member function aerial(), that takes a string as input and uses cout to print a phrase with the string.
  3. Then, we create the class Bird, which inherits Animal and Aerial with a private access modifier. Inside the Bird class-
    • We define a public member function called display().
    • This function inherits the animal() and aerial() methods from the Animal and Aerial class, respectively. 
  4. Inside the main() function, we first create an object B of class Bird.
  5. Then, using the dot operator and the object, we call the display() method while passing the string variable 'Eagle' as input. 
  6. This invokes the animal() and aerial() functions from the parent classes and prints the output to the console.

Also read: Multiple Inheritance In C++ & Diamond Problem Resolution (Examples)

Multilevel Inheritance In C++

In multilevel inheritance, a derived class becomes the base class for another derived class. As shown in the diagram above, class C inherits from class B, which in itself inherits from the class A. To better understand the concept, let's consider a simple example of the human biological relationships where we have three classes- Child, Parent, and Grandparents. Here, the Child class inherits from the Parent class, and the Parent class inherits from the Grandparent class.

Syntax Of Multilevel Inheritance In C++:

class B1 {
// Base class 1 members
};
class B2 : access_modifer B1 {
// Base class 2 members
};
class DerivedClass : access_modifier B2 {
// Derived class members
};

Here,

  • The class keyword indicates the creation of classes, including two base classes with names B1 and B2 and a derived class with the name DerivedClass.
  • access_modifier is the access specifier that determines how inherited members are visible in the derived class.

To further understand the concept of multi level inheritance in C++, let's take a look at an example C++ code which showcases the implementation of the same. 

Code Example:

Output:

This is a Vehicle.
This vehicle can fly in the air.
Aeroplane has wings.

Explanation:

In the code example above,

  1. We create a class Vehicle and define a constructor Vehicle() inside it, with a public access modifier. The function prints a string message- 'This is a Vehicle.' and the newline escape sequence shifts the cursor to the next line.
  2. Next, we create a derived class, FlyingObject, which inherits from Vehicle. Inside the class, we define the FlyingObject() constructor, which prints a phrase using cout. This makes the function publicly accessible to the inherited class objects.
  3. Following this, we create another class, Aeroplane, which inherits the FlyingObject class with the public access modifier.
  4. Inside the Aeroplane class, we use the public access modifier to define the display() constructor function, which inherits all the methods of the FlyingObject class.
  5. Inside the main() function, we create an object obj of class Aeroplane.
  6. This creation of the object of the Aeroplane class leads a chain of calls to constructors of all classes.
  7. The constructors are called in the sequence of inheritance, i.e., first the constructor of the base class FlyingObject is invoked, which further invokes the constructor of the base class of FlyingObject, i.e., class Vehicle.
  8. The output is printed to the console, and the program terminates with return 0.

Hybrid Inheritance In C++

Hybrid inheritance in C++ is a combination of more than one inheritance type within the same program. This is also called virtual inheritance in C++. For example, a complex hierarchy involving multiple types of inheritance. Since it is a combination of more than one inheritance, there is no fixed syntax for it. So, let's take a look at an example to get a better understanding of this concept.

Code Example:

Output

Enter the value of x: 4
Enter the value of y: 5
Enter the value of z: 6
The product of x, y, and z is: 120

Explanation:

In the code above-

  1. We begin by including the necessary headers and then create a class X, with a public data member x (of data type int) and the getX() function. The function takes an input value of the x variable using cin command.
  2. Next, we create a derived class Y, which publically inherits from class X. Inside the class, we declare an integer variable y and define the function getY().
  3. The getY() function prompts the user to input a value for y using cout, and it reads the value using cin.
  4. Following that, we create another class Z with an integer data member z and a getZ() function.
  5. Next, we create another class, A, which inherits from both Y and Z. Inside the class A, we declare an integer variable, d, and define a Product() function.
  6. The function invokes the functions from classes X, Y, Z, to get values for three variables, then calculates the product of the three variables using the multiplication arithmetic operator, and finally prints it to the console. 
  7. Inside the main() function, we create an object obj of class A and use this object with the dot operator to call the Product() function.
  8. As a result, functions getX(), getY(), and getZ() get called, prompting the user to input values of x, y, and z. 
  9. After the values are entered, the Product() function calculates the product, and the output is printed to the console. 

Note- Here, x = 4, y = 5, and z = 6 are taken as input. There is a single inheritance between classes X and Y. Multiple inheritance between classes A, Y, and Z. Class A inherits classes Y and Z. Multilevel inheritance between classes A, Y, and Z. Class Y inherits class X, and class A inherits class Y.

Hierarchical Inheritance In C++

In hierarchical inheritance, multiple derived classes inherit from a single base class, i.e., more than one child class inherits from a single parent class. For example, say we have a parent class Animal which consists of all types of animals. Then the Dog class, Cat class, Horse class, etc., are all sub-classes of Animal or all inherit from the Animal class.

Syntax For Hierarchial Inhertiance In C++:

class B {
// body of the class
}
class D1 : access_modifier B {
// body of the class
}
class D2 : access_modifier B {
// body of the class
}
class D3 : access_modifier B {
// body of the class
}

Here,

  • The keyword class indicates that we are declaring a class, and access_modifier indicates the mode of visibility for its members. 
  • B, D1, D2, and D3 refer to the names of the base/ parent class and its derived classes. 

Now, let's look at a C++ program that showcases how hierarchical inheritance works in action. 

Code Example:

Output

This is a fruit.
This is a fruit.

Explanation

The code example above shows how two classes, Mango and Durain, that inherit from the same base class, Fruit.

  1. First, we create the class Fruit with a public member function display(). This makes the function publicly accessible to the inherited class objects.
  2. The display() function prints the phrase 'This is a fruit.' to the console using the cout command
  3. Next, we create two derived classes, Mango and Durian, which inherit the Fruit class with the public access modifier. This way, Durian and Mango inherit the display method from the Fruit class.
  4. Inside the main() function, we create two objects, obj1 of class Mango and another object, obj2 of class Durian.
  5. We then use the dot operator to call the display() method on these objects, which they inherit from the Fruit class.
  6. As a result, the display() function prints the string message twice. This shows that the inherited classes can access the member function of the class they inherit from.

Check out this amazing course and participate in a coding sprint to supercharge your C++ programming skills!

Visibility Modes Of Inheritance In C++

Visibility modes control the accessibility of inherited members in the derived class. In other words, the visibility mode explains how the inherited members of the base class will be accessible to the derived class.

There are three access modes, i.e., public visibility mode, protected visibility mode, and private visibility mode. In this section, we will discuss these types of visibility modes in detail.

Public Visibility Mode Of Inheritance In C++

Public visibility mode is when we derive a class from a parent class with the public keyword. This is referred to as public inheritance, and all the members retain their visibility in the derived class.

That is, when we derive a class in public mode, the members of the base class that are public remain public in the derived class, members that are protected in the parent class remain protected in the derived class, and private members are inaccessible.

Syntax:

class DerivedClass : public BaseClass {
// Body of the class
}

Here,

  • The class keyword is used for creating a new class.
  • BaseClass and DerivedClass are the names of the nase/ parent and the derived/ child class, respectively.
  • The public keyword/ access specifier makes all the members inherited from the BaseClass public only if the members being inherited are public in the BaseClass.

Example Code:

Output:

This is an animal.

Explanation:

In this example for public visibility mode-

  1. We create a class Animal after including the necessary header files and namespace.
  2. Inside the Animal class, we define the speak() function, which prints a phrase using the cout command.
  3. When defining the function, we use the public access modifier to ensure that it is publicly accessible to all derived classes from anywhere in the program.
  4. Next, we create a class, Dog, which is derived from the Animal class, in public mode, which means objects of the Dog class can access the public members of the base class. 
  5. Inside the main() function, we create an object dog of the Dog class and use the dot operator to call the speak() function on the object. 
  6. This invokes the speak() function from the base class, and the output is printed to the console. 

So, as shown, the Dog class is derived from Animal, and the speak function from the Animal class is publicly accessible to the Dog class.

Protected Visibility Mode Of Inheritance In C++

The protected mode refers to the situation where we derive a class from a base class using the protected keyword. As a result of this, the protected and public members of the base class become protected in the derived class, and private members remain inaccessible.

And these protected members can only be accessed by the derived class and its member functions. Also, any subclass can inherit these protected members, with the exception of private members.  

Syntax:

class DerivedClass : protected BaseClass {
// body of the class
}

Here,

  • The class keyword, BaseClass, and DerivedClass all remain the same from the syntax for private visibility mode.
  • The access specifier protected here indicates that the derived class has protected inheritance. That is, all its members are protected only if inherited members are public or protected in BaseClass.

Now, let's take a look at an example to build a deeper understanding of this concept. 

Code Example:

Output:

This is an animal.

Explanation:

In the code example above,

  1. We create a parent class Animal with a public member function speak(), which prints a phrase using the cout command.
  2. Next, we create a derived class, Dog, using the protected keyword/ access modifier. This means that only the Dog class member functions can access the member functions of the Animal class, that too from inside the derived class only.
  3. We then define a display() function inside Dog, which further calls on the speak() function from the base class. 
  4. Inside the main() function, we create an object dog of the Dog class and call the display method using the dot operator.
  5. This invokes the speak() method inherited from the Animal class, and the result is shown in the output window.

Private Visibility Mode Of Inheritance In C++

The private mode of visibility also referred to as private inheritance, is when we derive a class with the use of the public keyword. In this case, all the members of the parent class (i.e., public, protected, or private) become private when inherited by the child class.

As a result, these members are only accessible inside the derived class or their access is restricted outside of the derived class. Also, only the member functions or friend functions of the derived class can access these private members. 

Syntax:

class DerivedClass : private BaseClass {
// body of the class
}

Here,

  • A major part of the syntax is the same as in the case of both the private and public visibility modes. The only difference is the access modifier and its implications. 
  • The private access specifier implies that all the inherited members from the base class turn private for the derived class.

Code Example:

Output

This is an animal.

Explanation

In the code example above-

  1. We first create a parent class called Animal, which contains a public member function speak() that prints a phrase using the cout command. and This means that the function is publicly accessible to the derived class.
  2. Next, we create a derived class, Dog, which inherits the Animal class with the private access modifier. This means that the member functions of the Animal class are only accessible inside the Dog class, not by its objects from outside of the class.
  3. The Dog class also contains a public member function display(), which contains the speak() function in the code body.
  4. Inside the main() function, we then create an object dog of the Dog class and use the dot operator to call the display() method.
  5. As mentioned, we can't use the object to call the parent class member function directly since the derived class is in private mode.
  6. So, we use the object to call the display() function, which further invokes the speak method from the Animal class.
  7. The result is then printed on the output console before the program terminates with a return 0.

Important Note:

If we were to use the object of the Dog class to call the speak() function directly, it would have generated an error. This is because the derived class inherits the parent class in private mode (i.e., private inheritance). So, as the Dog class privately inherits the Animal class, the member function of the Animal class is accessible only inside the Dog class, not by its objects outside of the class.

Access Modifiers & Inheritance In C++

Access modifiers, such as public, protected, and private, are used to control the visibility and accessibility of class members. They also play a role in inheritance in C++.

  • public: Members are accessible from any part of the program.
  • protected: Members are accessible within the class and inside its derived classes.
  • private: Members are accessible only within the class.

We use these access modifiers to define the visibility mode of a class for inheritance in C++, as discussed in the section above.

How To Make A Private Member Inheritable?

The private members are not inheritable from the base class to the derived class. This means the member functions of the base class are not accessible to the derived class and its objects. Private members of the base class can be inherited in the two following ways-

  • Changing the visibility mode of base class members from private to public. However, there is a point of concern with this method that is, it will remove the data-hiding property of the private access modifier.
  • Changing the visibility mode from private to protected. This method retains the data-hiding property of the private mode. Changing the private member to protected makes it inheritable and accessible within the class and to the member function of the derived class.

Code Example:

Output:

Base class method displayed.

Explanation:

In the C++ code example-

  1. We create a parent class called BaseClass with a protected member function called show(), which prints a phrase to the console using cout.
  2. The protected keyword makes the member functions of the BaseClass accessible only within the parent class or by the derived class, not by the objects of the derived class.
  3. We then create a DerivedClass class, which inherits the parent class with a public access modifier.
  4. The DerivedClass contains a public member function display() which invokes the show() method from the base class.
  5. Inside the main() function, we create an object obj of DerivedClass and use a dot operator to call the display() method
  6. As mentioned in the code comments, if we were to use the object to call the show() method, it would throw an error as the data is in protected mode. The data-hiding property will remain enforced.
  7. So, when we call the display method, it, in turn, invokes the show() method, and the output is displayed, as seen in the output window.

Member Function Overriding In Inheritance In C++

Member function overriding allows derived classes to provide their own implementations of a function that is already defined in the base class. To achieve this, you use the virtual keyword in the base class.

To understand this, consider the relationship between RBI (The Reserve Bank of India) and other banks like SBI, HDFC, ICICI, etc. Since RBI is the parent/ governing body that stipulates rules and regulations, all the banks follow the same regulatory functions and orders. However, each bank can override certain aspects of the rules, for example, the amount of loan that the bank has given, etc.

Syntax:

class Base {
public:
virtual returnType functionName(parameters) {
// Base class implementation
}
};
class Derived : public Base {
public:
returnType functionName(parameters) override {
// Derived class implementation
}
};

Here,

  • class Base { ... }: This defines a parent class named Base.
  • virtual returnType functionName(parameters) { ... }: In the base class, a virtual member function named functionName is declared. The virtual keyword indicates that this function can be overridden by derived classes.
  • returnType specifies the data type of the value the function returns, and parameters refer to the function's input values.
  • { // Base class implementation }: Within the curly braces, you define the implementation of the functionName in the base class.
  • class Derived: public Base { ... }: This defines a derived class named Derived, publicly inheriting from the base class Base.
  • returnType functionName(parameters) override { ... }: In the derived class, you declare a function with the same name, return type, and parameter list as in the base class.
  • The override keyword explicitly indicates that this function is intended to override the base class function.
  • { // Derived class implementation }: Here, you provide the specific implementation of the functionName in the derived class.

Code Example:

Output:

Calling speak() on Animal object:
Animal speaks.
Calling speak() on Dog object:
Dog barks.

Explanation:

In this example,

  1. We define a base class Animal with a virtual function speak(). The speak() function prints Animal speaks.
  2. Then, we create a derived class Dog that inherits from Animal. In the Dog class, we override the speak() function to print 'Dog barks'.
  3. In the main() function, we create two objects, Animal and Dog, of the base and child class, respectively, using the new operator.
  4. Then, we assign these objects to the pointers myAnimal and myDog.
  5. Next, we use the objects and 'this' pointer to call the speak() function on both objects.
  6. When we call myAnimal->speak(), it invokes the base class's speak() function, printing 'Animal speaks'.
  7. When we call myDog->speak(), it invokes the overridden function in the Dog class, printing 'Dog barks'.
  8. We delete the dynamically allocated objects to free memory.

The Diamond Problem | Inheritance In C++ & Ambiguity

The diamond problem is a specific issue that arises in object-oriented programming languages that support multiple inheritance in C++. It occurs when a class inherits from two or more classes that have a common base class. This situation can lead to ambiguity and complications in the inheritance hierarchy.

For example, from the above image, you can see that both Class B and Class C inherit Class A, i.e., they both inherit the same member functions of Class A. Also, Class D inherits both Class B and Class C, i.e., Class D indirectly will have two copies of Class A, one from Class B and another from Class C.

If we need to access the data member of Class A through the object of Class D, we must specify the path to access Class A, as the compiler can’t differentiate between the two copies of x in Class A in Class D.

Real-life analogy: 

Consider the following classes:

  1. Car Class (Parent Class)
  2. FuelCar Class
  3. ElectronicCar Class
  4. HybridCar Class

Now, the Car class consists of all car types (objects) and various functions like fuel consumption, average, breaking mechanism, etc. The classes FuelCar and ElectronicCar inherit from the parent class and have their own d definition of functions. So we have one parent class with two child classes.

Next, the HybridCar class inherits properties from both the segment of fuel and electronic cars. Now, here, the diamond problem will occur as follows:

  • FuelCar and ElectronicCar both share some common properties inherited from the Car class.
  • So when the HybridCar inherits from FuelCar and ElectronicCar, it will have two sets of the shared features it indirectly inherits from the Car class.

This gives rise to a conflict or ambiguity in the properties inherited from Car by both FuelCar and ElectronicCar. That is, the HybridCar may not know which version of the shared feature to inherit. This creates a diamond-like shape in the inheritance hierarchy as follows:

             Car
         /          \
FuelCar  ElectronicCar
        \            /
       HybridCar

In this family tree analogy:

  • Car represents a common base class with some shared properties.
  • FuelCar and ElectronicCar represent the derived classes, each inheriting from Car but potentially adding or modifying properties.
  • HybridCar represents a new generation that inherit from both FuelCar and ElectronicCar, potentially causing a conflict when there are conflicting properties or methods inherited from Car.

Ways To Avoid Ambiguity Inheritance In C++

Avoiding ambiguity in programming is essential for writing clear and error-free code. Ambiguity occurs when the compiler or interpreter cannot determine the correct interpretation of a statement due to multiple possible meanings. There are two ways to avoid ambiguity these are-

  • Using the Scope Resolution Operator
  • Using Virtual Keyword

We will discuss both these methods in detail in this section. 

Using the Scope Resolution Operator

You can use the scope resolution operator (::) to specify which base class member you want to access, i.e., it lets you manually specify the path from which the data member will be accessed.

Code Example:

Output:

The product is: 140

Explanation:

In the code example above,

  1. We first define a parent class A with a public data member, x, of data type integers.
  2. Next, we create two classes B and C, that inherit from class A in public mode. Both the classes contain one integer variable y and z respectively. 
  3. Then we create a fourth class D, which inherits from classes B and C. The use of public specifiers indicates public visibirly mode.
  4. In the main() function, we first create an object obj of class D. Then-
    • obj.B :: x = 4 sets the x variable in class A through the B part of obj.
    • obj.y = 5 sets the 'y' variable in class B.
    • obj.z = 7 sets the z variable in class C.
    • obj.product = obj.B :: x * obj.y * obj.z; calculates the product of x, y, and z, and stores it in the product variable.
    • cout << "The product is: " << obj.product << "\n" prints the product on the console, after which the program terminates.

Using Virtual Keyword

Although the scope resolution operator removes the ambiguous situation. But still, there are two copies of the base class in the derived class. To resolve this problem, you can use the virtual keyword and employ virtual inheritance. Here's an example:

Code Example:

Output:

The product is: 140

Explanation:

In the code example above,

  1. First, we create a class A and use the public access specifier to declare the integer variable x. This makes the variable publicly accessible to the inherited classes.
  2. Then, we create two other classes, class B and class C, both of which inherit class A in public mode with the virtual keyword. This makes only one copy of the base class to any derived child class, i.e., class D will have only one copy of x.
  3. Inside classes B and C, we use the public access specifier to declare the variables y and z, respectively.
  4. We then create class D, which inherits classes B and C with a public access specifier. Thus, it inherits the data members of B and C, with only one copy of the data members of class A.
  5. Inside class D, we use the public access modifier and declare an integer variable product.
  6. Inside the main() function, we create an object obj of class D. Since ambiguity is resolved, we can directly access the value of x without any error.
  7. We then use the product data member of obj to store the product of x, y, and z.
  8. Lastly, we use the cout class to display the product, as seen in the output window.

Why & When To Use Inheritance In C++?

Inheritance in C++ is a fundamental concept in object-oriented programming (OOP) that allows you to create new classes based on pre-existing classes.

  • Inheritance in C++ is used when you want to create a new class that shares attributes and behaviours of an existing class, forming an 'is-a' relationship.
  • It is particularly useful when you want to promote code reusability and maintainability by avoiding redundancy.
  • We also use inheritance in C++ when we have a hierarchy of related classes and we want to define a common base class that encapsulates shared functionality while allowing derived classes to extend or specialize that functionality.
  • Inheritance in C++ is also valuable when you want to leverage polymorphism to write more flexible and extensible code, enabling objects of different classes to be treated uniformly through a base class interface.

However, it's essential to carefully consider the design of your class hierarchy to ensure it accurately reflects the relationships between your objects and that inheritance in C++ is the most appropriate solution for your specific problem, as overusing inheritance can lead to complex and tightly coupled code.

Advantages Of Inheritance In C++

Inheritance in C++ offers a wide range of advantages varying from reusability to enabling polymorphism in the code. Some of these are mentioned below:

  • Code Reusability: Inheritance allows you to create a new class (the derived or subclass) based on an existing class (the base or superclass). This reuse of code is one of the primary benefits of inheritance in C++. You can avoid duplicating code by inheriting and extending existing classes.
  • Hierarchy and Organization: Inheritance in C++ enables you to create a hierarchy of classes that model real-world relationships. For example, you can create a hierarchy of shapes with a base class Shape and derived classes like Circle and Rectangle. This hierarchy can make your code more organized and intuitive.
  • Polymorphism: Inheritance is closely tied to polymorphism, which allows objects of different derived classes to be treated as objects of the base class. This essential feature enables you to write more generic and flexible code that can work with various derived classes without knowing their specific types.
  • Easier Maintenance: When you need to make changes to shared functionality or properties, you can do so in the base class, and those changes will automatically apply to all derived classes. This way, inheritance in C++ reduces the risk of errors and makes maintenance more efficient.
  • Specialization: Derived classes can specialize and add unique key features or behaviours to the base class. This specialization allows you to model specific aspects of your application accurately while maintaining a common interface through inheritance in C++.
  • Extensibility: Derived classes can extend and customize the functionality of base classes. This is also called as transitive nature of inheritance. For example, functional overriding in derived classes to perform specialized functions.
  • Modularity: Inheritance in C++ enhances code organization and maintainability. This makes code more meaningful and logical to understand.

The Disadvantages Of Inheritance In C++

There are various disadvantages of inheritance in C++, some of which are mentioned below:

  • Inflexible Class Hierarchies: Inheritance in C++ creates a strong relationship between base and derived classes. Once a class inherits from another, it's challenging to change that relationship without affecting the entire class hierarchy. This can lead to inflexible designs.
  • Tight Coupling: Inheritance in C++ can lead to tight coupling between classes. Changes in the base class can potentially impact all derived classes, making the codebase more fragile and harder to maintain.
  • Complexity: As class hierarchies grow, they can become complex and challenging to understand. Overuse of inheritance in C++ can lead to deep hierarchies that are difficult to manage and navigate.
  • Difficulty in Testing: When you inherit from a base class, you inherit its behaviour and possibly its dependencies. This can make unit testing more challenging, as you might need to deal with the behaviour of the base class, which may not be desirable in certain test scenarios.
  • Limited Multiple Inheritance: C++ supports multiple inheritance, but it can be complex and lead to the diamond problem, where ambiguity arises if a class inherits from two classes that have a common base class. This can make code more challenging to maintain and understand.

Conclusion

In conclusion, inheritance in C++ is a pivotal mechanism for building robust, reusable, and well-organized software.

  • By inheriting properties and methods from base classes, we can create specialized derived classes, model real-world hierarchies, and enhance code reusability.
  • Whether you're designing intricate class hierarchies or building modular frameworks, a solid grasp of inheritance is invaluable.

However, it's crucial to use this tool judiciously, considering factors like access specifiers, the diamond problem, and alternative strategies like composition. With careful planning and a clear understanding of inheritance in C++, you can craft elegant, maintainable, and adaptable C++ programs that stand the test of time.

Also read- 51 C++ Interview Questions For Freshers & Experienced (With Answers)

Frequently Asked Questions

Q. What are C++ access modifiers?

Access modifiers are the keywords that control the visibility or access of class members to the derived class. They also play a crucial role in inheritance in C++. These are public, protected, and private.

  • public: Members are accessible from any part of the program.
  • protected: Members are accessible within the class and inside its derived classes.
  • private: Members are accessible only within the class.

Q. What are the two levels of inheritance in C++?

There are two levels of Inheritance in C++, which are-

  1. Single-Level Inheritance- In single inheritance, a derived class inherits from a single base class, i.e., a child class inherits from a single parent class. For example, consider Vehicle as a base class and a Car as the child class inherited only from it.
  2. Multilevel Inheritance- In multilevel inheritance, a subclass becomes the base class for another derived class. For example, a Child class inherits from the Parent class, and a Parent class inherits from the Grandparent class.

Q. What is inheritance in C++ and its syntax?

Inheritance in C++ is a core concept of object-oriented programming (OOP) that allows you to create new classes (derived classes or subclasses) based on existing classes (base classes or superclasses). It enables a subclass to inherit all the properties of the base class and add some new features to itself.

Syntax Of Inheritance In C++:

class ParentClassName {
// class definition
};

class ChildClassName : visibility_mode ParentClassName {
// class definition
};

Here,

  • class: It is the keyword for creating a new class.
  • ParentClassName: It is the name of the base class or parent class.
  • ChildClassName: It is the name of the derived class or child class.
  • Visibility_mode: It is the access specifier that determines how inherited members are visible in the derived class (public, protected, or private).

Q. What is a constructor in C++?

In C++, a constructor is a special member function within a class that gets called automatically when we create an object of that class. Its primary purpose is to initialize the object's data members and perform all necessary setup tasks. Also, constructors have the same name as the class, and they do not have a return type.

A constructor typically initializes the object's state, allocates resources if necessary, and prepares the object for use. Here's a concise explanation of constructors in C++ with an example.

Code Example:

Output:

Constructor executed!

Explanation:

In the code example above,

  1. We first create a class Myclass and use the public access modifier to define the constructor member function Myclass(). This makes the function publicly accessible.
  2. Inside the main() function, we create an object obj of Myclass.
  3. This will automatically call the constructor function and execute it.
  4. It will show its output, as seen in the output window.

Q. Explain polymorphism in C++ with an example.

Polymorphism in C++ is a cool way of saying that objects can act differently based on their types, even if they belong to the same family of classes. Imagine it as a chameleon that can change color to camouflage with its surroundings. In C++, this is made possible through the use of base and derived classes. A base class sets up a blueprint for functions, and then its derived classes give their unique spin to those functions.

Code Example:

Output:

Circle drawn
Square drawn

Explanation:

  • The Shape class is defined as the base class with a virtual function draw().
  • The Circle class is derived from Shape and overrides the draw() function to print 'Circle drawn'.
  • The Square class is also derived from Shape and overrides the draw() function to print 'Square drawn'.
  • The drawShape function takes the reference to an object from Shape class and calls the draw() function on it, allowing polymorphism.
  • In the main() function, instances of Circle and Square are created.
  • drawShape(circle) calls the drawShape function with a Circle object, printing 'Circle drawn'.
  • drawShape(square); calls the drawShape function with a Square object, printing 'Square drawn'.
  • Finally, return 0; signals successful program execution.

Q. What is the scope resolution operator (::) in C++?

The scope resolution operator (::) in C++ is a critical element that serves various purposes in the codes/ programs. It is used to precisely specify the scope or context for accessing variables, functions, or members within C++ programs.

  • Accessing Global Entities: When there are variables or functions with the same name in different scopes (global and local), the scope resolution operator allows you to access the global version explicitly. This ensures that you're working with the targeted variable or function.
  • Accessing Static Class Members: When working with classes, especially static members (variables and functions), the scope resolution operator allows you to access these members associated with the class itself rather than any specific instance of the class.
  • Defining Member Functions Outside of Class: In C++, you can define member functions of a class outside of the class declaration for better organization and readability. The scope resolution operator specifies that the function belongs to a particular class.
  • Resolving Ambiguity: When you have variables or functions with the same name in different scopes (e.g., global and local), you can use the scope resolution operator to resolve the ambiguity and specify which one you want to use.

This compiles our discussion on inheritance in C++. Here are some more articles you might be interested in:

  1. Logical Operators In C++ | Use, Precedence & More (With Examples)
  2. Destructor In C++ | Understanding The Key To Cleanups (+ Examples)
  3. C++ Exception Handling | Use Try, Catch, & Throw (+Examples)
  4. Inline Function In C++ | Declare, Working, Examples & More!
  5. Constant In C++ | Literals, Objects, Functions & More (+Examples)
  6. Storage Classes In C++ & Its Types Explained (With Examples)
Shivani Goyal
Manager, Content

An economics graduate with a passion for storytelling, I thrive on crafting content that blends creativity with technical insight. At Unstop, I create in-depth, SEO-driven content that simplifies complex tech topics and covers a wide array of subjects, all designed to inform, engage, and inspire our readers. My goal is to empower others to truly #BeUnstoppable through content that resonates. When I’m not writing, you’ll find me immersed in art, food, or lost in a good book—constantly drawing inspiration from the world around me.

TAGS
Computer Science Engineering
Updated On: 27 Mar'24, 12:21 AM IST