Inheritance in C++ : Concepts, Types, and Practical Examples

Updated on August 31, 2024

Article Outline

Does maintaining your C++ code turn into a nightmare that keeps getting worse as your project gets bigger?

 

We’ve all been there writing the same logic over again or trying to figure out how to structure code, so it’s easy to maintain.

 

That is, the inheritance in C++ comes into play.

 

Inheritance is the ability of a class to acquire the attributes and characteristics of a different class. One may see it as being much like the transfer of traits from parent to child, but in which the child is not an exact duplicate.

Inheritance in C++

Why Inheritance is a Fundamental Concept in Object-Oriented Programming

Inheritance is not a mere buzzword; it is the cornerstone of Object-Oriented Programming.

 

Now, let’s say we have to design some complicated system where each component has some common functionality. Rather than reinventing the wheel each time, we can define a base class with shared features and then have other classes inherit from it.

 

In this way, we save a little bit of time and make our code more maintainable.

 

Consider the development of a software system for the library.

 

We may have a superclass like LibraryItem that would hold fields like title, author, and ISBN. Then we could be able to create more generic classes, such as Book, Magazine, and DVD.

 

Each of these could inherit the common attributes while adding their particular features.

*Image
Get curriculum highlights, career paths, industry insights and accelerate your technology journey.
Download brochure

Different Modes of Inheritance in C++ and How They Impact Access Control

When it comes to C++ inheritance, it is important to know about the various types-public, protected, and private.

 

These modes will determine how the deriving class gets to access inherited stuff from the base class and, finally, how objects of the derived class can use them, too.

Inheritance in C++

Public Inheritance

In public inheritance, though being the most commonly used form, all the public members of the base class remain public in the derived class, and ‘protected’ remains ‘protected’.

 

However, the private members are not directly accessible from the derived class, but if needed, they can be accessed through the public or protected methods of the base class.

 

Example:

#include <iostream> using namespace std; class Vehicle { public: string brand; void honk() { cout << "Beep! Beep!" << endl; } }; class Car : public Vehicle { public: string model; void showDetails() { cout << "Brand: " << brand << ", Model: " << model << endl; } }; int main() { Car myCar; myCar.brand = "Toyota"; myCar.model = "Corolla"; myCar.honk(); myCar.showDetails(); return 0; }

Output:

Beep! Beep! Brand: Toyota, Model: Corolla

In this example, the Car class publicly inherits from Vehicle, so brand and honk() are directly accessible in Car.

Protected Inheritance

In protected inheritance, all the members that are public and protected in the base class become protected in the derived class.

 

It means they cannot be accessed from other classes apart from the derived class, but they can be accessed within the derived class and other sub-classes of the derived class.

 

Example:

#include <iostream> using namespace std;   class Person { protected: string name; int age; public: void setDetails(string n, int a) { name = n; age = a; } };   class Employee : protected Person { public: void setEmployeeDetails(string n, int a) { setDetails(n, a);  // Accessing the protected setDetails method } void display() { cout << "Name: " << name << ", Age: " << age << endl; } };   int main() { Employee emp; emp.setEmployeeDetails("Shivani", 30); emp.display(); return 0; }

Output:

Name: Shivani, Age: 30

 

Here, Employee inherits from Person using protected inheritance.

 

The name and age attributes, though set through a public method, are protected in Employee and can’t be accessed directly outside of it.

Private Inheritance

In private inheritance, both the public and protected members of base classes become private in the derived classes.

 

This implies that they can only be invoked by the derived class and not even by other sub-classes of that class.

 

Example:

#include <iostream> using namespace std;   class Animal { public: void eat() { cout << "Eating..." << endl; } };   class Dog : private Animal { public: void bark() { cout << "Barking..." << endl; eat(); // eat() is private in Dog, but accessible within the class } };   int main() { Dog myDog; myDog.bark(); // myDog.eat(); // This will cause a compile-time error return 0; }

Output:

Barking... Eating...

Here, the Dog class privately inherits from Animal. The eat() function is accessible within Dog, but trying to call it outside of Dog results in an error.

Exploring the Various Types of Inheritance in C++ with Detailed Examples

Multiple Level Inheritence

Single Inheritance: Keeping it Simple with One Base Class

In single inheritance, a derived class inherits from just one base class.

 

This is the most basic form of inheritance.

 

Imagine we have a base class called LibraryItem with common attributes like title and author. We can create a derived class called Book that adds more specific features like ISBN.

Single Inheritance in C++

Example:

 

In this example, Book inherits from LibraryItem, making it easy to manage shared properties like title and author without rewriting code.

#include <iostream> using namespace std;   class LibraryItem { public: string title; string author; void getInfo() { cout << "Title: " << title << ", Author: " << author << endl; } };   class Book : public LibraryItem { public: string ISBN; void getBookInfo() { getInfo(); cout << "ISBN: " << ISBN << endl; } };   int main() { Book myBook; myBook.title = "1984"; myBook.author = "George Orwell"; myBook.ISBN = "123-4567890123"; myBook.getBookInfo(); return 0; }

Output:

Title: 1984, Author: George Orwell ISBN: 123-4567890123

Multiple Inheritance: Mixing Features from Multiple Base Classes

Sometimes, a single base class isn’t enough. We might need a class that combines features from more than one base class.

 

This is where multiple inheritance comes into play.

 

Consider creating a Smartphone class that inherits from both Camera and Phone. This lets us mix features like taking photos and making calls.

Multiple Inheritance

Example:

#include <iostream> using namespace std;   class Camera { public: void takePhoto() { cout << "Photo taken!" << endl; } };   class Phone { public: void makeCall() { cout << "Calling..." << endl; } };   class Smartphone : public Camera, public Phone { public: void showFeatures() { takePhoto(); makeCall(); } };   int main() { Smartphone myPhone; myPhone.showFeatures(); return 0; }

Output:

Photo taken! Calling...

Here, the Smartphone inherits from both the Camera and Phone, enabling it to use functionalities from both classes.

Multilevel Inheritance: Building on Top of Inherited Features

What if we need a class that inherits from another derived class?

 

Multiple inheritance enables one class to inherit from another derived class, forming a hierarchy of inheritance.

 

Suppose we have a base class, Animal, a derived class, Mammal and another derived class – Human. These components are closely intertwined; each stage is constructed based on the previous one.

Multilevel Inheritance in c++

Example:

#include <iostream> using namespace std;   class Animal { public: void breathe() { cout << "Breathing..." << endl; } };   class Mammal : public Animal { public: void walk() { cout << "Walking..." << endl; } };   class Human : public Mammal { public: void speak() { cout << "Speaking..." << endl; } };   int main() { Human person; person.breathe(); person.walk(); person.speak(); return 0; }

Output:

Breathing... Walking... Speaking...

Here, Human inherits from Mammal, which in turn inherits from Animal. This creates a hierarchy where each class adds more specific functionality.

Hierarchical Inheritance: Sharing a Base Class Across Multiple Derived Classes

In hierarchical inheritance, multiple classes share the same base class. This is useful when different classes need to inherit the same basic features.

 

Imagine a base class Shape with derived classes like Rectangle, Circle, and Triangle. Each shape shares some common properties like area.

Hierarchical Inheritance

Example:

#include <iostream> using namespace std;   class Shape { public: void setDimensions(int a, int b) { dimension1 = a; dimension2 = b; } protected: int dimension1, dimension2; };   class Rectangle : public Shape { public: int area() { return dimension1 * dimension2; } };   class Triangle : public Shape { public: int area() { return (dimension1 * dimension2) / 2; } };   int main() { Rectangle rect; Triangle tri;   rect.setDimensions(10, 20); tri.setDimensions(10, 20);   cout << "Rectangle area: " << rect.area() << endl; cout << "Triangle area: " << tri.area() << endl;   return 0; }

Output:

Rectangle area: 200 Triangle area: 100

Here, Rectangle and Triangle share the base class Shape, allowing us to reuse the setDimensions method.

Hybrid Inheritance: Combining Multiple Inheritance Types

Hybrid inheritance combines more than one type of inheritance. This often happens when classes are part of a more complex system.

 

For example, we could combine single and multiple inheritance to create a class structure that manages devices.

Hybrid Inheritance

Example:

#include <iostream> using namespace std;   class Device { public: void powerOn() { cout << "Device powered on!" << endl; } };   class Printer : virtual public Device { public: void print() { cout << "Printing document..." << endl; } };   class Scanner : virtual public Device { public: void scan() { cout << "Scanning document..." << endl; } };   class AllInOne : public Printer, public Scanner { public: void useDevice() { powerOn(); print(); scan(); } };   int main() { AllInOne machine; machine.useDevice(); return 0; }

Output:

Device powered on! Printing document... Scanning document...

In this example, AllInOne inherits from both the Printer and Scanner, which both inherit from the Device.

 

This allows AllInOne to use features from both classes while avoiding the diamond problem through virtual inheritance.

Addressing the Diamond Problem in Multiple Inheritance and its Solutions

Have you ever faced a situation where two parent classes share a common base class?

 

If you have done so, you also likely have encountered what is called the diamond problem in C++ inheritance.

 

One such problem arises when a derived class is inheriting from two classes, and both classes are again inheriting from the same base class. This problem has been so named because the inheritance diagram drawn from this appears like a diamond.

What Exactly is the Diamond Problem?

Now, assuming for explanation purposes, let there be a base class Device, and then two derived classes Printer and Scanner, each derived from the base class Device.

 

Suppose, for example, we make another class, say, AllInOne, which inherits from both the classes Printer and Scanner. Again, this makes two copies of a Device to be in AllInOne.

 

This can lead to confusion and ambiguity, especially with access to the base class members.

 

Example of the Diamond Problem

#include <iostream> using namespace std;   class Device { public: void powerOn() { cout << "Device powered on!" << endl; } };   class Printer : public Device { };   class Scanner : public Device { };   class AllInOne : public Printer, public Scanner { };   int main() { AllInOne machine; machine.powerOn(); // Ambiguity: which powerOn() to call? return 0; }

This code won’t compile because the compiler doesn’t know whether to use the powerOn() method from Printer or Scanner.

Solving the Diamond Problem with Virtual Inheritance

To solve this, we use virtual inheritance.

 

By declaring the base class as virtual, we ensure that only one copy of the base class is inherited and hence avoiding the ambiguity.

#include <iostream> using namespace std;   class Device { public: void powerOn() { cout << "Device powered on!" << endl; } };   class Printer : virtual public Device { };   class Scanner : virtual public Device { };   class AllInOne : public Printer, public Scanner { };   int main() { AllInOne machine; machine.powerOn(); // No ambiguity return 0; }

Output:

Device powered on!

Here, by making the Device a virtual base class, both the Printer and Scanner share a single copy of the Device.

This resolves the diamond problem, allowing AllInOne to call powerOn() without any ambiguity.

Advantages of Using Inheritance in C++ for Code Reusability and Extensibility

Inheritance in C++ offers significant advantages:

 

  1. Code Reusability:
    • By inheriting from a base class, we can reuse code without rewriting it.
    • This reduces errors and saves time.
  2. Extensibility:
    • Inheritance allows us to extend existing classes with new features.
    • This makes it easier to maintain and update code over time.
  3. Improved Code Organisation:
    • Using inheritance, we can organise our code into logical hierarchies.
    • This makes it easier to understand and manage complex systems.
  4. Polymorphism:
    • Inheritance enables polymorphism, where a base class reference can point to derived class objects.
    • This flexibility is crucial for designing scalable and maintainable software.

 

Also Check: C++ Tutorial

Practical Applications of Inheritance in Real-World C++ Projects

Inheritance in GUI Applications

Suppose someone begins developing a Graphical User Interface (GUI); he or she has to conceptualise and code numerous elements, including buttons, text boxes, and sliders.

 

Although these components are very similar and have parameters such as position and size in common, they act differently.

 

Another advantage that comes from the creation of such classes as Widget is that we can create subclasses such as Button and TextField. This enables us to avoid writing the same code all over again and also makes our application more consistent.

 

Example:

#include <iostream> using namespace std;   class Widget { public: int x, y; virtual void draw() = 0; // Pure virtual function };   class Button : public Widget { public: string label; void draw() override { cout << "Drawing button at (" << x << ", " << y << ") with label: " << label << endl; } };   class TextField : public Widget { public: string text; void draw() override { cout << "Drawing text field at (" << x << ", " << y << ") with text: " << text << endl; } };   int main() { Button btn; btn.x = 50; btn.y = 100; btn.label = "Submit"; btn.draw();   TextField tf; tf.x = 60; tf.y = 150; tf.text = "Enter your name"; tf.draw();   return 0; }

Output:

Drawing button at (50, 100) with label: Submit Drawing text field at (60, 150) with text: Enter your name

Conclusion

Inheritance in C++ is all about code reuse and extension, as in any other OOP language. This turns out to be one of the ways of obtaining clean, scalable and maintainable code therefore managing complexities in systems.

It helps developers to create organised and well-structured codebases, thanks to the different forms of inheritance and its implications on access control.

Accomplished through effective use of inheritance, allowing the codebase to expand with the project, support additional features without losing manageability, and reduce the pains of updating later on.

Using inheritance is a smarter way of coding and allows us to get better while writing more powerful software.

FAQs
Public inheritance allows the derived class to access public and protected members of the base class. Protected inheritance makes the inherited members protected in the derived class, while private inheritance makes them private.
Virtual inheritance ensures that a single copy of the base class is shared among all derived classes, avoiding the ambiguity of multiple copies.
Yes, a derived class can override a base class method if it’s declared as virtual in the base class.
Yes, C++ supports multiple inheritance, allowing a class to inherit from more than one base class.
Common pitfalls include improper use of access specifiers, not using virtual functions when necessary, and creating overly complex inheritance hierarchies.

Updated on August 31, 2024

Link
left dot patternright dot pattern

Programs tailored for your success

Popular

IIT Courses

Management

Data Science

Finance

Technology

Future Tech

Upskill with expert articles

View all
Hero Vired logo
Hero Vired is a leading LearnTech company dedicated to offering cutting-edge programs in collaboration with top-tier global institutions. As part of the esteemed Hero Group, we are committed to revolutionizing the skill development landscape in India. Our programs, delivered by industry experts, are designed to empower professionals and students with the skills they need to thrive in today’s competitive job market.
Blogs
Reviews
Events
In the News
About Us
Contact us
Learning Hub
18003093939     ·     hello@herovired.com     ·    Whatsapp
Privacy policy and Terms of use

|

Sitemap

© 2024 Hero Vired. All rights reserved