Understanding Inheritance in CPP Programming Language
Object-oriented programming (OOP) is a programming paradigm that uses objects to represent real-world entities. Inheritance is one of the fundamental concepts in OOP that enables code reuse and reduces code duplication. In C++, inheritance is implemented through the use of classes. In this article, we will discuss inheritance in C++ programming language, its types, and how to use it effectively.
Introduction to Inheritance in CPP
Inheritance is one of the fundamental concepts of object-oriented programming (OOP) in CPP. It allows us to create new classes that reuse, extend, and modify the behavior of existing classes. In this blog post, we will explore what inheritance is, how it works, and why it is useful in CPP.
What is inheritance?
Inheritance is a way of creating a new class from an existing class. The new class is called a derived class or a child class, and the existing class is called a base class or a parent class. The derived class inherits all the data members and member functions of the base class, and can also add new ones or override the existing ones.
Why use inheritance in CPP?
Inheritance has many benefits in CPP programming, such as:
- Code reuse: We can reuse the code of the base class in the derived class without having to rewrite it. This reduces duplication and improves maintainability.
- Polymorphism: We can use a pointer or a reference of the base class type to access objects of the derived class type. This allows us to write generic code that can work with different types of objects that share a common base class.
- Abstraction: We can define abstract classes that specify the interface of a group of related classes, but do not provide any implementation details. The derived classes can then implement the abstract methods according to their own logic. This helps us to hide the complexity and focus on the essential features of a problem.
Syntax of Inheritance in CPP
In C++, inheritance is implemented using the ‘class’ keyword. The derived class is declared using the ‘class’ keyword followed by the derived class name, and then a colon followed by the access specifier and the name of the base class. The access specifier can be ‘public’, ‘private’ or ‘protected’. The access specifier determines how the members of the base class are accessible to the derived class.
The syntax for declaring a derived class is as follows:
class DerivedClass : access-specifier BaseClass
{
// Declaration of members
};
Example of Inheritance in CPP
Let’s consider an example of a base class called ‘Person’ that contains two data members, ‘name’ and ‘age’, and a member function called ‘displayDetails()’. We will create a derived class called ‘Student’ that inherits from the ‘Person’ class and adds a new data member called ‘rollNo’.
#include <iostream>
using namespace std;
class Person {
public:
string name;
int age;
void displayDetails() {
cout << "Name: " << name << endl;
cout << "Age: " << age << endl;
}
};
class Student : public Person {
public:
int rollNo;
};
int main() {
Student s;
s.name = "John";
s.age = 20;
s.rollNo = 12345;
s.displayDetails();
cout << "Roll Number: " << s.rollNo << endl;
return 0;
}
In this example, the ‘Student’ class is derived from the ‘Person’ class using the ‘public’ access specifier. The ‘Student’ class contains an additional data member called ‘rollNo’. In the ‘main’ function, we create an object of the ‘Student’ class and assign values to its data members. We also call the ‘displayDetails()’ member function of the ‘Person’ class using the ‘Student’ object. Finally, we display the value of the ‘rollNo’ data member using the ‘cout’ statement.
Types of Inheritance in CPP
In CPP, we can use different access specifiers to control how the members of the base class are inherited by the derived class.
There are three types of inheritance in CPP as per their different access specifiers.
- Public Inheritance: This is the most common type of inheritance in CPP. It means that all the public members of the base class are also public in the derived class, and all the protected members of the base class are also protected in the derived class. The private members of the base class are not accessible in the derived class.
- Protected Inheritance: This means that all the public and protected members of the base class are protected in the derived class. The private members of the base class are not accessible in the derived class.
- Private Inheritance: This means that all the public and protected members of the base class are private in the derived class. The private members of the base class are not accessible in the derived class.
The inheritance can also be classified as per their use with below types:
- Single Inheritance.
- Multiple Inheritance.
- Hierarchical Inheritance.
- Multi-Level Inheritance.
Single Inheritance in CPP
Single Inheritance is a concept in object-oriented programming where a subclass or derived class inherits the properties and behaviors of a single superclass or base class. In other words, it is a way of creating a new class by extending an existing class.
The single inheritance relationship forms a hierarchy of classes, where each subclass inherits the attributes and methods of its superclass and can add its own unique attributes and methods.
Here’s an example of single inheritance in C++:
class Shape {
protected:
double width;
double height;
public:
Shape(double w, double h) {
width = w;
height = h;
}
virtual double area() {
return 0;
}
};
class Rectangle: public Shape {
public:
Rectangle(double w, double h): Shape(w, h) {}
double area() override {
return width * height;
}
};
class Triangle: public Shape {
public:
Triangle(double w, double h): Shape(w, h) {}
double area() override {
return 0.5 * width * height;
}
};
In this example, we have a base class Shape
that defines some common properties and behaviors of all shapes. It has a constructor that initializes the width
and height
of the shape, and a virtual
method area
that calculates the area of the shape. The virtual
keyword indicates that this method can be overridden by subclasses.
Then, we define two subclasses Rectangle
and Triangle
that inherit from Shape
. The Rectangle
and Triangle
classes have their own constructors that call the constructor of the base class Shape
to initialize the width
and height
attributes.
The Rectangle
class overrides the area
method of its parent class to calculate the area of a rectangle, while the Triangle
class overrides the area
method to calculate the area of a triangle.
Now, we can create instances of the Shape
, Rectangle
, and Triangle
classes and use their methods:
Shape* s1 = new Rectangle(5, 10);
cout << s1->area() << endl; // output: 50
Shape* s2 = new Triangle(5, 10);
cout << s2->area() << endl; // output: 25
As we can see, the Rectangle
and Triangle
classes inherit the width
and height
attributes and the area
method from their parent class Shape
, and override the area
method to calculate the area of their respective shapes. We use a pointer of type Shape*
to refer to objects of both Rectangle
and Triangle
classes because they are both derived from Shape
.
Multiple Inheritance in CPP
Multiple inheritance is an object-oriented programming concept where a subclass or derived class inherits properties and behaviors from multiple parent classes or base classes. In other words, it is a way of creating a new class by combining the features of two or more existing classes.
In C++, multiple inheritance is a mechanism by which a class can inherit properties and behaviors from multiple base classes. It allows creating a new class by combining the features of two or more existing classes.
class Flyer {
public:
virtual void fly() {
cout << "Flying" << endl;
}
};
class Swimmer {
public:
virtual void swim() {
cout << "Swimming" << endl;
}
};
class Duck: public Flyer, public Swimmer {
public:
void quack() {
cout << "Quack quack!" << endl;
}
};
In C++, multiple inheritance is a mechanism by which a class can inherit properties and behaviors from multiple base classes. It allows creating a new class by combining the features of two or more existing classes.
Here’s an example of multiple inheritance in C++:
cppCopy codeclass Flyer {
public:
virtual void fly() {
cout << "Flying" << endl;
}
};
class Swimmer {
public:
virtual void swim() {
cout << "Swimming" << endl;
}
};
class Duck: public Flyer, public Swimmer {
public:
void quack() {
cout << "Quack quack!" << endl;
}
};
In this example, we have two base classes Flyer
and Swimmer
that define some common properties and behaviors of objects that can fly and swim, respectively. Each class has a virtual
method fly
and swim
, respectively, that prints a message indicating that the object is flying or swimming.
Then, we define a subclass Duck
that inherits from both Flyer
and Swimmer
classes using multiple inheritance. The Duck
class has its own method quack
that simply prints the message “Quack quack!”.
Now, we can create instances of the Duck
class and use its methods:
Duck d1;
d1.fly(); // output: Flying
d1.swim(); // output: Swimming
d1.quack(); // output: Quack quack!
As we can see, the Duck
class inherits the fly
method from its parent class Flyer
and the swim
method from its parent class Swimmer
, and adds its own quack
method. This allows us to create objects that have the properties and behaviors of both a flyer and a swimmer.
Hierarchical Inheritance in CPP
Hierarchical inheritance is an object-oriented programming concept where a subclass or derived class inherits properties and behaviors from a single base class, but the base class has multiple derived classes. In other words, it is a way of creating a new class by specializing an existing class that has multiple derived classes.
Here’s an example of hierarchical inheritance in C++:
class Shape {
protected:
double width;
double height;
public:
Shape(double w, double h) {
width = w;
height = h;
}
virtual double area() {
return 0;
}
};
class Rectangle: public Shape {
public:
Rectangle(double w, double h): Shape(w, h) {}
double area() override {
return width * height;
}
};
class Triangle: public Shape {
public:
Triangle(double w, double h): Shape(w, h) {}
double area() override {
return 0.5 * width * height;
}
};
class Square: public Rectangle {
public:
Square(double s): Rectangle(s, s) {}
};
In this example, we have a base class Shape
that defines some common properties and behaviors of all shapes. It has a constructor that initializes the width
and height
of the shape, and a virtual
method area
that calculates the area of the shape.
Then, we define two subclasses Rectangle
and Triangle
that inherit from Shape
. The Rectangle
and Triangle
classes have their own constructors that call the constructor of the base class Shape
to initialize the width
and height
attributes.
The Rectangle
class overrides the area
method of its parent class to calculate the area of a rectangle, while the Triangle
class overrides the area
method to calculate the area of a triangle.
Finally, we define another subclass Square
that inherits from Rectangle
. The Square
class has its own constructor that calls the constructor of its parent class Rectangle
to initialize the width
and height
attributes with the same value. This allows us to create a specialized type of rectangle that always has equal width and height.
Now, we can create instances of the Shape
, Rectangle
, Triangle
, and Square
classes and use their methods:
Shape* s1 = new Rectangle(5, 10);
cout << s1->area() << endl; // output: 50
Shape* s2 = new Triangle(5, 10);
cout << s2->area() << endl; // output: 25
Shape* s3 = new Square(5);
cout << s3->area() << endl; // output: 25
As we can see, the Rectangle
and Triangle
classes inherit the width
and height
attributes and the area
method from their parent class Shape
, and override the area
method to calculate the area of their respective shapes. The Square
class inherits the width
and height
attributes and the area
method from its parent class Rectangle
, and specializes the rectangle by always having equal width and height. This allows us to create objects that have the properties and behaviors of a rectangle, triangle, or square, and to specialize the rectangle to create a square.
Multi-level Inheritance in CPP
Multi-level inheritance is an object-oriented programming concept where a subclass or derived class inherits properties and behaviors from a single base class, which in turn is derived from another base class. In other words, it is a way of creating a new class by extending an existing derived class.
Here’s an example of multi-level inheritance in C++:
class Shape {
protected:
double width;
double height;
public:
Shape(double w, double h) {
width = w;
height = h;
}
virtual double area() {
return 0;
}
};
class Rectangle: public Shape {
public:
Rectangle(double w, double h): Shape(w, h) {}
double area() override {
return width * height;
}
};
class Square: public Rectangle {
public:
Square(double s): Rectangle(s, s) {}
};
class Cuboid: public Rectangle {
protected:
double depth;
public:
Cuboid(double w, double h, double d): Rectangle(w, h) {
depth = d;
}
double volume() {
return width * height * depth;
}
};
In this example, we have a base class Shape
that defines some common properties and behaviors of all shapes. It has a constructor that initializes the width
and height
of the shape, and a virtual
method area
that calculates the area of the shape.
Then, we define a subclass Rectangle
that inherits from Shape
. The Rectangle
class has its own constructor that calls the constructor of the base class Shape
to initialize the width
and height
attributes. The Rectangle
class overrides the area
method of its parent class to calculate the area of a rectangle.
Next, we define another subclass Square
that inherits from Rectangle
. The Square
class has its own constructor that calls the constructor of its parent class Rectangle
to initialize the width
and height
attributes with the same value. This allows us to create a specialized type of rectangle that always has equal width and height.
Finally, we define another subclass Cuboid
that inherits from Rectangle
. The Cuboid
class has an additional attribute depth
to specify the depth of the cuboid. It has its own constructor that calls the constructor of the Rectangle
class to initialize the width
and height
attributes, and initializes the depth
attribute separately. The Cuboid
class also has a volume
method that calculates the volume of the cuboid by multiplying the width
, height
, and depth
attributes.
Now, we can create instances of the Shape
, Rectangle
, Square
, and Cuboid
classes and use their methods:
Shape* s1 = new Rectangle(5, 10);
cout << s1->area() << endl; // output: 50
Shape* s2 = new Square(5);
cout << s2->area() << endl; // output: 25
Cuboid* c1 = new Cuboid(5, 10, 15);
cout << c1->area() << endl; // output: 50
cout << c1->volume() << endl; // output: 750
As we can see, the Rectangle
and Square
classes inherit the width
and height
attributes and the area
method from their parent class Shape
, and override the area
method to calculate the area of their respective shapes.
The Cuboid
class inherits the width
and height
attributes and the area
method from its parent class Rectangle
, and adds an additional depth
attribute to represent the depth of the cuboid. The Cuboid
class also adds a volume
method that calculates the volume of the cuboid by multiplying the width
, height
, and depth
attributes.
Advantages of Inheritance in CPP
Inheritance in C++ is a key feature of object-oriented programming. Here are some of the main advantages of using inheritance:
- Code Reusability and Recycling: Classes that are derived from a base class can use all the functions that were declared and defined in the base class. This means that the derived class does not need to write those functions again.
- Transitive Nature: If class B is derived from class A and class C is derived from class B, class C will inherit the properties of both class B and class A. Hence, the inheritance in C++ is transitive in nature.
- Data Hiding: Inheritance can also be used to implement data hiding or encapsulation. The base class can keep private data that it wants to hide from the outside world, and expose operations that are permitted on that data through public methods.
- Overriding and Polymorphism: Derived classes can override functions of the base class, which allows for polymorphism. This makes the program more customizable and flexible, and can make code easier to read and maintain.
- Extensibility: New capabilities can be added to a program without extensively modifying existing classes. A new derived class can be created with additional attributes and methods, extending the functionality of the base class.
- Hierarchy Representation: Inheritance allows programmers to create a hierarchical representation of classes which can be very useful in certain types of programming problems.
- Cost-Effective: Inheritance helps in reducing the cost of development since the reusability of code reduces the overall lines of code, leading to cost savings.
- Faster Development: As derived classes can reuse code from the base classes, it can lead to a faster development process.
Disadvantages of Inheritance in CPP
While inheritance is a powerful feature of C++, like any other programming construct, it has potential downsides if not used properly. Here are some of the main disadvantages of using inheritance in C++:
- Increased Complexity: Inheritance can make the code more difficult to read and understand, especially when multiple levels of inheritance are used. This can lead to issues with code maintenance and debugging.
- Tight Coupling: Inheritance creates a tight coupling between the base class and the derived class. If changes are made to the base class, it can potentially break functionality in the derived classes. This can make the code less flexible and harder to maintain.
- Hidden Parent Class Behavior: Derived classes can unintentionally use inherited functionality which can lead to bugs that are difficult to track down. This is particularly problematic when using multiple inheritance, as it’s not always clear which parent class a particular method or property is inherited from.
- Overriding Issues: If methods are overridden incorrectly, it can lead to unexpected behavior, which can be difficult to debug.
- Inheritance Hierarchies: Deep inheritance hierarchies can lead to confusion and can make the code harder to maintain. As a general rule, it’s better to prefer composition over inheritance when the inheritance hierarchy starts to become too deep.
- Multiple Inheritance: C++ supports multiple inheritance, which can lead to a lot of confusion when two base classes have a method with the same name. This can also lead to the dreaded “diamond problem” where a class inherits from two classes that both inherit from a single base class, leading to ambiguity in the inheritance hierarchy.
- Encapsulation Breakdown: Inheritance can sometimes lead to a breakdown in encapsulation, because subclassing exposes a subclass to details it shouldn’t necessarily have knowledge of. This can lead to code that is hard to modify without unintended side effects.
Future Development and Enhancement of Inheritance in CPP
Certainly, here are potential future developments and enhancements to inheritance in C++, presented point-by-point:
- Enhancements in Code Readability: The C++ community could focus on making inheritance syntax and usage more readable and easy to understand. This might help to reduce complexity and ambiguity, especially in large codebases.
- Improved Error Checking: Future versions of C++ might provide better compile-time and runtime error checking for inheritance-related code. This could help catch common errors and make the code more robust.
- Better Support for Composition Over Inheritance: Given the trend towards favoring composition over inheritance, C++ might introduce features that make composition easier and more efficient. This could include enhancements to the way objects are combined and managed.
- Concepts for Inheritance: Concepts, a feature introduced in C++20, could be more widely applied to inheritance. This would allow developers to specify exactly what behaviors a derived class should implement, making the code more flexible and less prone to errors.
- Refinement of Multiple Inheritance: While multiple inheritance is powerful, it can also be confusing. Future versions of C++ might refine the way multiple inheritance works to reduce potential problems, like the “diamond problem”.
- Optimization of Inheritance Hierarchies: There could be improvements in the optimization of inheritance hierarchies, to ensure better performance and memory usage.
- Better Encapsulation: Enhancements might be made to how inheritance works with private and protected members of a class, further strengthening the encapsulation principle.
- Better Integration with Modern C++ Features: As C++ continues to evolve, new features may be developed that work seamlessly with inheritance, such as newer template metaprogramming techniques, constexpr functions, etc.