Hierarchical Inheritance in C++: Simplifying Code Reusability and Maintenance
Basics of SQL
12 Hrs. duration
12 Modules
2600+ Learners
Start Learning
Suppose you are working on a huge project with lots of intersections between the different parts of your code. Now, imagine that you have a Person class, which you want to use as the base for Employee, Manager, and Intern. They all share the same basic attributes: name and age. But they each have their own distinctive features, too.
That’s where hierarchical inheritance in C++ comes into play.
When we code, repetition is about the most frustrating thing that happens. At best, having to write the same functions over and over again for each class is inefficient; at worst, a headache.
Through hierarchical inheritance, we would be able to reuse our code effectively once for one base class, such as Person, and have multiple derived classes, such as Employee, Manager, and so on, which will inherit common properties and methods from their base class.
The magic of hierarchical inheritance in C++ lies in its simplicity. It cuts down our workload and helps us keep things neat and tidy. That’s exactly why it’s a cornerstone in object-oriented programming (OOP).
Core Structure and Characteristics of Hierarchical Inheritance in C++
What does hierarchical inheritance actually look like? It’s like a family tree-one parent, many children. And they all inherit that parent’s traits, but each has his or her own features.
In the case of hierarchical inheritance, one base class and several derived classes are there: the base class maintains the common properties, and the derived classes extend those properties to specialize in their own tasks. Think of it like this:
Base Class (Person): This is where all the common properties live. Things like name, age, and address.
Derived Classes: These are classes like Employee, Manager, and Intern. Each inherits the basic features of Person and adds more specific details like salary or team size.
Here’s a simple code snippet showing the structure:
#include<iostream>
using namespace std;
// Base class
class Person {
public:
string name;
int age;
void getDetails() {
cout << "Enter name: ";
cin >> name;
cout << "Enter age: ";
cin >> age;
}
};
// Derived class 1
class Employee : public Person {
public:
int salary;
void showEmployeeDetails() {
getDetails();
cout << "Enter salary: ";
cin >> salary;
cout << "Employee Name: " << name << ", Age: " << age << ", Salary: " << salary << endl;
}
};
// Derived class 2
class Manager : public Person {
public:
int teamSize;
void showManagerDetails() {
getDetails();
cout << "Enter team size: ";
cin >> teamSize;
cout << "Manager Name: " << name << ", Age: " << age << ", Team Size: " << teamSize << endl;
}
};
int main() {
Employee emp;
Manager mgr;
emp.showEmployeeDetails();
cout << endl;
mgr.showManagerDetails();
return 0;
}
Output:
Enter name: Rahul
Enter age: 30
Enter salary: 55000
Employee Name: Rahul, Age: 30, Salary: 55000
Enter name: Priya
Enter age: 38
Enter team size: 60
Manager Name: Priya, Age: 38, Team Size: 60
Step-by-Step Explanation of Syntax for Implementing Hierarchical Inheritance
The syntax for coding hierarchical inheritance in C++ is simple. We start off by setting the base class. Under this class fall all the properties and methods needed throughout the derived classes. After setting the base class, we set the derived classes. In each of the derived classes, properties belonging to the base class are inherited using the public keyword. This allows the derived class to have access to the public members of the base class.
Here’s the general syntax for hierarchical inheritance:
class Base {
// base class members
};
class Derived1 : public Base {
// derived class members
};
class Derived2 : public Base {
// another derived class
};
Above, Derived1 and Derived2 inherit from Base. That means, of course, that any member functions or data members in Base can be accessed by both derived classes.
Now, let’s take a more realistic example. We have used the class Person previously, but let’s add a little more depth to it now:
class Person {
public:
string name;
int age;
void getDetails() {
cout << "Enter your name: ";
cin >> name;
cout << "Enter your age: ";
cin >> age;
}
};
class Employee : public Person {
public:
string position;
void getPosition() {
cout << "Enter your position: ";
cin >> position;
}
void display() {
cout << name << " is " << age << " years old and works as a " << position << "." << endl;
}
};
class Manager : public Employee {
public:
void displayManager() {
getDetails();
getPosition();
cout << name << " is " << age << " years old and is a manager in " << position << " department." << endl;
}
};
In this example, Manager is also inheriting from Employee, which in turn inherits from Person. This shows how hierarchical inheritance can extend over multiple levels.
Visibility Modes in Hierarchical Inheritance and Their Impact on Access Control
When using hierarchical inheritance in C++, one of the most important factors to consider is how visibility modes affect the access control of the inherited members. There are three types of visibility modes in C++:
Public: The public members of the base class remain public in the derived class.
Protected: Public and protected members of the base class become protected in the derived class.
Private: Public and protected members of the base class become private in the derived class.
These visibility modes play a huge role in controlling access to the base class members from within the derived class.
Here’s an example demonstrating the use of public visibility:
class Person {
public:
string name;
int age;
};
class Employee : public Person {
public:
void display() {
cout << "Name: " << name << ", Age: " << age << endl; // Accessible due to public visibility
}
};
In the example above, both name and age are accessible in the derived class because they are public members of the base class.
But let’s see what happens when we change the visibility mode to private:
class Person {
public:
string name;
int age;
};
class Employee : private Person {
public:
void display() {
// Error: name and age are now private in Employee
cout << "Name: " << name << ", Age: " << age << endl;
}
};
This results in an error because private inheritance makes name and age private in the derived class, preventing access outside the class itself.
Understanding visibility modes is crucial when working with hierarchical inheritance, as they define what data can be accessed and from where.
Practical Examples of Hierarchical Inheritance in Real-World Systems
Now, let’s really get into some real-world ways we can use hierarchical inheritance in C++.
Now, suppose that one has to work on handling the database of a school. Records about students, teachers, and administrative staff are to be dealt with.
Some common characteristics which all the above groups possess are name, age, address, etc. Each has their special properties, though: the students have grades, teachers have subjects they teach, and the administrative staff have roles.
Hierarchical inheritance works best here.
We can create a base class Person and then derive classes for each group.
Here’s how it works:
#include<iostream>
using namespace std;
// Base class
class Person {
public:
string name;
int age;
void getPersonDetails() {
cout << "Enter name: ";
cin >> name;
cout << "Enter age: ";
cin >> age;
}
};
// Derived class for Students
class Student : public Person {
public:
string grade;
void getStudentDetails() {
getPersonDetails();
cout << "Enter grade: ";
cin >> grade;
cout << "Student: " << name << ", Age: " << age << ", Grade: " << grade << endl;
}
};
// Derived class for Teachers
class Teacher : public Person {
public:
string subject;
void getTeacherDetails() {
getPersonDetails();
cout << "Enter subject: ";
cin >> subject;
cout << "Teacher: " << name << ", Age: " << age << ", Subject: " << subject << endl;
}
};
// Derived class for Admin Staff
class AdminStaff : public Person {
public:
string role;
void getAdminDetails() {
getPersonDetails();
cout << "Enter role: ";
cin >> role;
cout << "Admin Staff: " << name << ", Age: " << age << ", Role: " << role << endl;
}
};
int main() {
Student student1;
Teacher teacher1;
AdminStaff admin1;
student1.getStudentDetails();
cout << endl;
teacher1.getTeacherDetails();
cout << endl;
admin1.getAdminDetails();
return 0;
}
Output:
Enter name: Amit
Enter age: 16
Enter grade: 10
Student: Amit, Age: 16, Grade: 10
Enter name: Manoj
Enter age: 28
Enter subject: Science
Teacher: Manoj, Age: 28, Subject: Science
Enter name: Pooja
Enter age: 27
Enter role: Office Manager
Admin Staff: Pooja, Age: 27, Role: Office Manager
In this example, Person is our base class. Each derived class (Student, Teacher, AdminStaff) has its own attributes while inheriting the common properties from Person. This structure makes it easy to organize and extend your code when managing different people in a system like a school.
Key Advantages of Hierarchical Inheritance for Code Reusability and Maintenance
So, why should we care about using hierarchical inheritance in C++? Because it makes our lives easier. Here’s how:
Code Reusability: We don’t need to write the same properties like name and age over and over for every class. Instead, we define them once in the base class, and the derived classes get them for free.
Cleaner Code: When we look at our code, it’s neatly organized into a structure that reflects the real-world relationships. It makes it easier to understand and maintain.
Easier Maintenance: If we need to change how name is handled, we only do it in one place (the base class), and it automatically updates across all derived classes.
Reduced Redundancy: By using hierarchical inheritance, we avoid repetitive code. This keeps our project lean and efficient.
Now, let’s get these benefits into perspective. Consider our school system. Suppose we had to remake the name and age attributes in each class. First of all, it would take more time, and it would be a pain to maintain. Instead, with hierarchical inheritance, we define those shared attributes once inside the base class, and they are inherited by all the rest of the classes. That’s the type of efficiency that allows us to keep our code maintainable, especially when the systems are bigger.
Common Issues and Best Practices for Using Hierarchical Inheritance Efficiently
While hierarchical inheritance in C++ saves our lives, it doesn’t come without its own set of problems.
Common Issues We Face
1.Ambiguity Between Inherited Functions
Suppose that you have two derived classes, each having a function with the name calculateSalary(). If another class inherits from both, the compiler is confused about which function is to be called.
Solution: Use virtual functions or avoid naming conflicts in your derived classes.
2. Accessing Private Members of the Base Class
Private members in the base class are not accessible in the derived classes. This is sometimes a problem if we need direct access to such members.
Solution: The base class can provide getter and setter methods that safely allow access to private data.
3. Overcomplication of Class Hierarchies
That’s very easy to get carried away with and build a deep and complex class hierarchy. This makes the code harder to understand and maintain.
Solution: Keep it simple. Inheritance should be used only when necessary to make sense and not beyond 2 or 3 levels of depth unless absolutely necessary.
4.Diamond Problem
This happens in multiple inheritances when a class inherits from two classes, both of which inherit the same base class. This causes ambiguity on which property or method to inherit.
Solution: The Diamond Problem can be solved by using virtual inheritance. Although this does not directly apply to hierarchical inheritance, it’s good to know this when working with more complicated inheritance models.
Best Practices for Hierarchical Inheritance
Just to enable us to avoid these problems, the following are some best practices that one should try to follow:
Keep Class Hierarchies Simple: Don’t overcomplicate things. If your hierarchy gets too deep, that is a signal you may want to rethink your structure.
Properly Using Access Specifiers: Knowing when to use public, private, and protected inheritance depending on the context of the classes you have.
Use Virtual Functions Where Necessary: This prevents any ambiguity and thus provides you with the flexibility of overriding the functions in derived classes.
Comment Your Code: Include comments that explain how your classes are related to one another. This makes it easier for others and also for yourself to get an overview of how things are structured.
Test Regularly: Every time you make changes to the base class, test all derived classes to ensure nothing is broken.
These best practices will help you avoid common pitfalls and realize the real power of C++ hierarchical inheritance in C++.
Real-World Example 1: Designing a Library System with Hierarchical Inheritance
Let’s discuss one way the library system could be arranged:
We have various types of items: books, magazines, and DVDs. Each item has some common details to say – a title and a publication date. They then have their own specific details.
For example, a book might have an author and page count, whereas a DVD would have a runtime. This can easily be modeled using hierarchical inheritance in C++.
We will start with a base class, LibraryItem, which contains the common information, and then go ahead with the derived classes for Book, Magazine, and DVD containing their specific attributes.
Let’s walk through the code for this system:
#include<iostream>
using namespace std;
// Base class
class LibraryItem {
public:
string title;
string publicationDate;
void getItemDetails() {
cout << "Enter title: ";
cin.ignore(); // Clears the input buffer
getline(cin, title); // Use getline for strings with spaces
cout << "Enter publication date (DD-MM-YYYY): ";
getline(cin, publicationDate); // Use getline to read the date as a string
}
};
// Derived class for books
class Book : public LibraryItem {
public:
string author;
int pageCount;
void getBookDetails() {
getItemDetails();
cout << "Enter author: ";
getline(cin, author); // Using getline to capture author's full name with spaces
cout << "Enter page count: ";
cin >> pageCount;
displayBookDetails();
}
void displayBookDetails() {
cout << "Book: " << title << ", Author: " << author << ", Pages: " << pageCount << ", Published on: " << publicationDate << endl;
}
};
// Derived class for magazines
class Magazine : public LibraryItem {
public:
int issueNumber;
void getMagazineDetails() {
getItemDetails();
cout << "Enter issue number: ";
cin >> issueNumber;
displayMagazineDetails();
}
void displayMagazineDetails() {
cout << "Magazine: " << title << ", Issue Number: " << issueNumber << ", Published on: " << publicationDate << endl;
}
};
// Derived class for DVDs
class DVD : public LibraryItem {
public:
int runtime;
void getDVDDetails() {
getItemDetails();
cout << "Enter runtime in minutes: ";
cin >> runtime;
displayDVDDetails();
}
void displayDVDDetails() {
cout << "DVD: " << title << ", Runtime: " << runtime << " mins, Published on: " << publicationDate << endl;
}
};
int main() {
Book book1;
Magazine mag1;
DVD dvd1;
cout << "Enter details for the book:n";
book1.getBookDetails();
cout << endl;
cout << "Enter details for the magazine:n";
mag1.getMagazineDetails();
cout << endl;
cout << "Enter details for the DVD:n";
dvd1.getDVDDetails();
return 0;
}
Output:
Enter details for the book:
Enter title: C++ Primer
Enter publication date (DD-MM-YYYY): 01-05-2020
Enter author: Lippman
Enter page count: 970
Book: ++ Primer, Author: Lippman, Pages: 970, Published on: 01-05-2020
Enter details for the magazine:
Enter title: Tech Magzine
Enter publication date (DD-MM-YYYY): 12-08-2021
Enter issue number: 45
Magazine: Tech Magzine, Issue Number: 45, Published on: 12-08-2021
Enter details for the DVD:
Enter title: The Matrix
Enter publication date (DD-MM-YYYY): 15-03-2003
Enter runtime in minutes: 150
DVD: The Matrix, Runtime: 150 mins, Published on: 15-03-2003
Real-World Example 2: Employee Management System Using Hierarchical Inheritance
Let’s look at the employee management system of a company.
Different roles that the employees can have are: manager, developer, intern. All employees share some basic information about themselves, such as name, employeeID, department; however, what role each one plays is unique.
In C++, using hierarchical inheritance, we can model the base class Employee and then derive separate classes for each of the different roles.
Here’s how we can build this system:
#include<iostream>
using namespace std;
// Base class
class Employee {
public:
string name;
int employeeID;
string department;
void getEmployeeDetails() {
cout << "Enter name: ";
cin >> name;
cout << "Enter employee ID: ";
cin >> employeeID;
cout << "Enter department: ";
cin >> department;
}
};
// Derived class for Managers
class Manager : public Employee {
public:
int teamSize;
void getManagerDetails() {
getEmployeeDetails();
cout << "Enter team size: ";
cin >> teamSize;
displayManagerDetails();
}
void displayManagerDetails() {
cout << "Manager: " << name << ", ID: " << employeeID << ", Department: " << department << ", Team Size: " << teamSize << endl;
}
};
// Derived class for Developers
class Developer : public Employee {
public:
string programmingLanguage;
void getDeveloperDetails() {
getEmployeeDetails();
cout << "Enter programming language: ";
cin >> programmingLanguage;
displayDeveloperDetails();
}
void displayDeveloperDetails() {
cout << "Developer: " << name << ", ID: " << employeeID << ", Department: " << department << ", Language: " << programmingLanguage << endl;
}
};
// Derived class for Interns
class Intern : public Employee {
public:
int duration; // duration in months
void getInternDetails() {
getEmployeeDetails();
cout << "Enter internship duration in months: ";
cin >> duration;
displayInternDetails();
}
void displayInternDetails() {
cout << "Intern: " << name << ", ID: " << employeeID << ", Department: " << department << ", Duration: " << duration << " months" << endl;
}
};
int main() {
Manager mgr;
Developer dev;
Intern intern;
mgr.getManagerDetails();
cout << endl;
dev.getDeveloperDetails();
cout << endl;
intern.getInternDetails();
return 0;
}
Output:
Enter name: Pooja
Enter employee ID: 1
Enter department: HR
Enter team size: 10
Manager: Pooja, ID: 1, Department: HR, Team Size: 10
Enter name: Neha
Enter employee ID: 2
Enter department: Development
Enter programming language: Java
Developer: Neha, ID: 2, Department: Development, Language: Java
Enter name: Shubham
Enter employee ID: 3
Enter department: Marketing
Enter internship duration in months: 6
Intern: Shubham, ID: 3, Department: Marketing, Duration: 6 months
Conclusion
Hierarchical inheritance in C++ allows the simplification of complex systems into related classes grouped around a common base class. It facilitates code reusability without redundancy, thus making the systems extensible.
By creating a structured hierarchy of classes, we can build applications that mirror real-world relationships, whether it’s managing a library system or handling employee roles in a company.
This model of inheritance is useful for keeping our code neat and clean, easy to maintain, and concise.
Hierarchical inheritance in C++ allows object-oriented programming, if well planned, to turn into a powerful tool for extending projects in time, keeping everything well organized and flexible towards any kind of growth.
FAQs
What is hierarchical inheritance in C++?
Hierarchical inheritance is when more than one subclass is derived from a single base class. It offers code reusability and allows the programmer to keep common characteristics between classes by managing programs easily.
In hierarchical inheritance, is it possible that the derived classes have their properties?
Yes, each derived class may have its unique properties and methods as well as inheriting common ones from the base class.
How does hierarchical inheritance help in real-world programming?
It saves us from redundancy, hence the reusability of code; it manages those complex systems that share common properties but also have specialized attributes.
What is the difference between public and private inheritances in hierarchical inheritance?
In public inheritance, the public members of the base class remain public in the derived class. In private inheritance, those members become private and hence restrict access outside the class.
Is it possible to extend hierarchical inheritance over many levels?
Yes, the concept of hierarchical inheritance can be extended over several levels, i.e., a derived class may itself become a base class to some other class, adding more levels in a hierarchy of class inheritance.
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.