C++ Inheritance
Inheritance is one of the key features of Object-oriented programming in C++.
It allows us to create a new class (derived class) from an existing class (base
class).
The derived class inherits the features from the base class and can have
additional features of its own. For example,
class Animal {
// eat() function
// sleep() function
};
class Dog : public Animal {
// bark() function
};
Here, the Dog class is derived from the Animal class. Since Dog is derived
from Animal, members of Animal are accessible to Dog.
The capability of a class to derive properties and characteristics from another
class is called Inheritance. Inheritance is one of the most important features
of Object Oriented Programming in C++. In this article, we will learn about
inheritance in C++, its modes and types along with the information about how
it affects different properties of the class.
Syntax of Inheritance in C++
class derived_class_name : access-specifier base_class_name
// body ....
};
is-a relationship
Inheritance is an is-a relationship. We use inheritance only if an is-a
relationship is present between the two classes.
Here are some examples:
● A car is a vehicle.
● Orange is a fruit.
● A surgeon is a doctor.
● A dog is an animal.
● // C++ program to demonstrate inheritance
● #include <iostream>
● using namespace std;
● // base class
● class Animal {
● public:
● void eat() {
● cout << "I can eat!" << endl;
● }
● void sleep() {
● cout << "I can sleep!" << endl;
● }
● };
● // derived class
● class Dog : public Animal {
● public:
● void bark() {
● cout << "I can bark! Woof woof!!" << endl;
● }
● };
● int main() {
● // Create object of the Dog class
● Dog dog1;
● // Calling members of the base class
● [Link]();
● [Link]();
● // Calling member of the derived class
● [Link]();
●
● return 0;
● }
● Output
● I can eat!
● I can sleep!
● I can bark! Woof woof!!
C++ protected Members
The access modifier protected is especially relevant when it comes to C++
inheritance.
Like private members, protected members are inaccessible outside of the
class. However, they can be accessed by derived classes and friend classes/
functions.
We need protected members if we want to hide the data of a class, but still
want that data to be inherited by its derived classes.
Example 2 : C++ protected Members
// C++ program to demonstrate protected members
#include <iostream>
#include <string>
using namespace std;
// base class
class Animal {
private:
string color;
protected:
string type;
public:
void eat() {
cout << "I can eat!" << endl;
}
void sleep() {
cout << "I can sleep!" << endl;
}
void setColor(string clr) {
color = clr;
}
string getColor() {
return color;
}
};
// derived class
class Dog : public Animal {
public:
void setType(string tp) {
type = tp;
}
void displayInfo(string c) {
cout << "I am a " << type << endl;
cout << "My color is " << c << endl;
}
void bark() {
cout << "I can bark! Woof woof!!" << endl;
}
};
int main() {
// Create object of the Dog class
Dog dog1;
// Calling members of the base class
[Link]();
[Link]();
[Link]("black");
// Calling member of the derived class
[Link]();
[Link]("mammal");
// Using getColor() of dog1 as argument
// getColor() returns string data
[Link]([Link]());
return 0;
}
Run Code
Output
I can eat!
I can sleep!
I can bark! Woof woof!!
I am a mammal
My color is black
Here, the variable type is protected and is thus accessible from the derived
class Dog. We can see this as we have initialized type in the Dog class using
the function setType().
On the other hand, the private variable color cannot be initialized in Dog.
class Dog : public Animal {
public:
void setColor(string clr) {
// Error: member "Animal::color" is inaccessible
color = clr;
}
};
Also, since the protected keyword hides data, we cannot access type directly
from an object of Dog or Animal class.
// Error: member "Animal::type" is inaccessible
[Link] = "mammal";
The various ways we can derive classes are known as access modes. These
access modes have the following effect:
1. public: If a derived class is declared in public mode, then the members
of the base class are inherited by the derived class just as they are.
2. private: In this case, all the members of the base class
become private members in the derived class.
3. protected: The public members of the base class
become protected members in the derived class.
The private members of the base class are always private in the derived class.
C++ Multilevel Inheritance
In C++ programming, not only can you derive a class from the base class but
you can also derive a class from the derived class. This form of inheritance is
known as multilevel inheritance.
class A {
... .. ...
};
class B: public A {
... .. ...
};
class C: public B {
... ... ...
};
Here, class B is derived from the base class A and the class C is derived from
the derived class B.
Example 1: C++ Multilevel Inheritance
#include <iostream>
using namespace std;
class A {
public:
void display() {
cout<<"Base class content.";
}
};
class B : public A {};
class C : public B {};
int main() {
C obj;
[Link]();
return 0;
}
Run Code
Output
Base class content.
In this program, class C is derived from class B (which is derived from base
class A).
C++ Multiple Inheritance
In C++ programming, a class can be derived from more than one parent. For
example, A class Bat is derived from base classes Mammal and WingedAnimal
. It makes sense because bat is a mammal as well as a winged animal.
Example 2: Multiple Inheritance in C++ Programming
#include <iostream>
using namespace std;
class Mammal {
public:
Mammal() {
cout << "Mammals can give direct birth." << endl;
}
};
class WingedAnimal {
public:
WingedAnimal() {
cout << "Winged animal can flap." << endl;
}
};
class Bat: public Mammal, public WingedAnimal {};
int main() {
Bat b1;
return 0;
}
Run Code
Output
Mammals can give direct birth.
Winged animal can flap.
C++ Hierarchical Inheritance
If more than one class is inherited from the base class, it's known
as hierarchical inheritance. In hierarchical inheritance, all features that are
common in child classes are included in the base class.
For example, Physics, Chemistry, Biology are derived from Science class.
Similarly, Dog, Cat, Horse are derived from Animal class.
Syntax of Hierarchical Inheritance
class base_class {
... .. ...
}
class first_derived_class: public base_class {
... .. ...
}
class second_derived_class: public base_class {
... .. ...
}
class third_derived_class: public base_class {
... .. ...
}
Example 3: Hierarchical Inheritance in C++ Programming
// C++ program to demonstrate hierarchical inheritance
#include <iostream>
using namespace std;
// base class
class Animal {
public:
void info() {
cout << "I am an animal." << endl;
}
};
// derived class 1
class Dog : public Animal {
public:
void bark() {
cout << "I am a Dog. Woof woof." << endl;
}
};
// derived class 2
class Cat : public Animal {
public:
void meow() {
cout << "I am a Cat. Meow." << endl;
}
};
int main() {
// create object of Dog class
Dog dog1;
cout << "Dog Class:" << endl;
[Link](); // parent Class function
[Link]();
// create object of Cat class
Cat cat1;
cout << "\nCat Class:" << endl;
[Link](); // parent Class function
[Link]();
return 0;
}
Run Code
Output
Dog Class:
I am an animal.
I am a Dog. Woof woof.
Cat Class:
I am an animal.
I am a Cat. Meow.
Hybrid Inheritance in C++
Hybrid inheritance is a complex form of inheritance in object-oriented
programming (OOP). In Hybrid Inheritance, multiple types of inheritance are
combined within a single class hierarchy, enabling a varied and flexible
structure of classes. In hybrid inheritance, within the same class, we can have
elements of single inheritance, multiple inheritance, multilevel inheritance, and
hierarchical inheritance.
Hybrid Inheritance
The major goal of hybrid inheritance is to enhance code reusability by making
it simpler for programmers to use the methods and attributes that are already
present in other classes. Hybrid inheritance has several advantages over other
inheritances as it increases the reusability of software elements, enables
quicker code development lowers coding errors by avoiding code duplication
across classes, and establishes a more clearly defined relationship between
classes in object-oriented programming. It also provides a structured way to
organize classes with shared attributes and behaviors.
Example 1: Using Single Inheritance and Multiple Inheritance
Let us consider a scenario where we have a base class “Person”, a derived
class “Employee” that uses single inheritance, and another derived class
“Student” that also uses single inheritance but combines with “Employee” to
create a hybrid inheritance.
Example:
// C++ program to illustrate the hybrid inheritance
#include <bits/stdc++.h>
using namespace std;
// Base class
class Person {
protected:
string name;
public:
Person(const string& name)
: name(name)
void display() { cout << "\nName: " << name << endl; }
};
// Derived class 1: Employee (Single Inheritance)
class Employee : public Person {
protected:
int employeeId;
public:
Employee(const string& name, int id)
: Person(name)
, employeeId(id)
void displayEmployee()
display();
cout << "Employee ID: " << employeeId << endl;
cout << "Method inside Derived Class Employee"
<< endl;
};
// Derived class 2: Student (Single Inheritance)
class Student : public Person {
protected:
int studentId;
public:
Student(const string& name, int id)
: Person(name)
, studentId(id)
void displayStudent()
display();
cout << "Student ID: " << studentId << endl;
cout << "Method inside Derived Class Student"
<< endl;
};
// Derived class 3: StudentIntern (Multiple Inheritance)
class StudentIntern : public Employee, public Student {
public:
StudentIntern(const string& name, int empId, int stuId)
: Employee(name, empId)
, Student(name, stuId)
{
void displayStudentIntern()
cout << "Methods inside Derived Class "
"StudentIntern : "
<< endl;
displayEmployee();
displayStudent();
};
// driver code
int main()
StudentIntern SI("Riya", 67537, 2215);
[Link]();
return 0;
}
Output
Methods inside Derived Class StudentIntern :
Name: Riya
Employee ID: 67537
Method inside Derived Class Employee
Name: Riya
Student ID: 2215
Method inside Derived Class Student
Is-A Relationship Example in C++
In C++. the Is-A relationship depends on inheritance. It is used for code
reusability in C++. For example, a Tomato is a vegetable, a Car is a vehicle, a
TV is an electronic device, and so on. For a better understanding, please have
a look at the below example.
#include <iostream>
using namespace std;
class Rectangle
{
public:
int length;
int breadth;
int Area()
{
return length * breadth;
}
int Perimeter ()
{
return 2 * (length + breadth);
}
};
class Cuboid:public Rectangle
{
public:
int height;
Cuboid(int l, int b, int h)
{
length = l;
breadth = b;
height = h;
}
int Volume ()
{
return length * breadth * height;
}
};
int
main ()
{
Cuboid c (2, 4, 6);
cout << "Volume is " << [Link]() << endl;
cout << "Area is " << [Link]() << endl;
cout << "Perimeter is " << [Link]() << endl;
}
Association, Composition and Aggregation in C++
In C++, an association is a relationship between two classes where one class
“has a” relationship with the other class. In other words, an instance of one
class has an instance of the other class as a member. This is a way of
modeling real-world relationships between objects in an object-oriented
programming language.
For example, consider a class “Person” and a class “Address”. If a person “has
an” address, we can say that there is an association between the two classes.
We can implement this association in C++ as follows:
class Address {
// Class members and methods
};
class Person {
Address address;
// Class members and methods
};
In this example, an instance of the “Person” class has an instance of the
“Address” class as a member, representing the association between the two
classes. The relationship between the two classes can also be represented
using a UML (Unified Modeling Language) diagram, which is a graphical
representation of the classes and their relationships.
Composition
In C++, composition is a special type of association between classes that
represents a stronger relationship than a regular association. In a composition
relationship, one class is the owner of the other class and is responsible for its
creation and destruction. This relationship is often referred to as a “has-a”
relationship, because one class has an instance of another class as a member.
A composition relationship is represented in C++ as an object of one class
being contained within another class. The contained object is said to be a part
of the containing object, and it cannot exist independently of the containing
object. If the containing object is destroyed, the contained object is
automatically destroyed along with it.
For example, consider a class Car and a class Engine. If a car "has an" engine,
we can say that there is a composition relationship between the two classes.
We can implement this composition relationship in C++ as follows:
class Engine {
// Class members and methods
};
class Car {
Engine engine;
// Class members and methods
};
In this example, an instance of the Engine class is contained within an
instance of the Car class, representing the composition relationship between
the two classes. The contained object engine cannot exist independently of
the containing object Car, and if the Car object is destroyed, the Engine object
is automatically destroyed along with it.
Aggregation
In C++, aggregation is a special type of association between classes that
represents a weaker relationship than a composition. In an aggregation
relationship, one class is a container for objects of another class, but it is not
responsible for the creation or destruction of those objects. This relationship is
often referred to as a “has-a” relationship, because one class has objects of
another class as members.
An aggregation relationship is represented in C++ as an object of one class
containing pointers to objects of another class. The contained objects are said
to be part of the containing object, but they can exist independently of the
containing object. If the containing object is destroyed, the contained objects
are not automatically destroyed along with it.
For example, consider a class Department and a class Employee. If a
department "has many" employees, we can say that there is an aggregation
relationship between the two classes. We can implement this aggregation
relationship in C++ as follows:
class Employee {
// Class members and methods
};
class Department {
std::vector<Employee*> employees;
// Class members and methods
};
In this example, an instance of the Department class contains pointers to
objects of the Employee class, representing the aggregation relationship
between the two classes. The contained objects employees can exist
independently of the containing object Department, and if
the Department object is destroyed, the Employee objects are not
automatically destroyed along with it.
Interfaces in C++ (Abstract Classes)
An interface describes the behavior or capabilities of a C++ class without
committing to a particular implementation of that class.
The C++ interfaces are implemented using abstract classes and these
abstract classes should not be confused with data abstraction which is a
concept of keeping implementation details separate from associated data.
A class is made abstract by declaring at least one of its functions as pure
virtual function. A pure virtual function is specified by placing "= 0" in its
declaration as follows −
class Box {
public:
// pure virtual function
virtual double getVolume() = 0;
private:
double length; // Length of a box
double breadth; // Breadth of a box
double height; // Height of a box
};
The purpose of an abstract class (often referred to as an ABC) is to provide an
appropriate base class from which other classes can inherit. Abstract classes
cannot be used to instantiate objects and serves only as an interface.
Attempting to instantiate an object of an abstract class causes a compilation
error.
Thus, if a subclass of an ABC needs to be instantiated, it has to implement
each of the virtual functions, which means that it supports the interface
declared by the ABC. Failure to override a pure virtual function in a derived
class, then attempting to instantiate objects of that class, is a compilation
error.
Classes that can be used to instantiate objects are called concrete classes.
Abstract Class Example
Consider the following example where parent class provides an interface to
the base class to implement a function called getArea() −
Open Compiler
#include <iostream>
using namespace std;
// Base class
class Shape {
public:
// pure virtual function providing interface framework.
virtual int getArea() = 0;
void setWidth(int w) {
width = w;
}
void setHeight(int h) {
height = h;
}
protected:
int width;
int height;
};
// Derived classes
class Rectangle: public Shape {
public:
int getArea() {
return (width * height);
}
};
class Triangle: public Shape {
public:
int getArea() {
return (width * height)/2;
}
};
int main(void) {
Rectangle Rect;
Triangle Tri;
[Link](5);
[Link](7);
// Print the area of the object.
cout << "Total Rectangle area: " << [Link]() << endl;
[Link](5);
[Link](7);
// Print the area of the object.
cout << "Total Triangle area: " << [Link]() << endl;
return 0;
}
When the above code is compiled and executed, it produces the following
result −
Total Rectangle area: 35
Total Triangle area: 17
You can see how an abstract class defined an interface in terms of getArea()
and two other classes implemented same function but with different
algorithm to calculate the area specific to the shape.
Inheritance Ambiguity in C++
In multiple inheritances, when one class is derived from two or more base
classes then there may be a possibility that the base classes have functions
with the same name, and the derived class may not have functions with that
name as those of its base classes. If the derived class object needs to access
one of the similarly named member functions of the base classes then it
results in ambiguity because the compiler gets confused about which base’s
class member function should be called.
Example:
// C++ program to show inheritance ambiguity
#include<iostream>
using namespace std;
// Base class A
class A {
public:
void func() {
cout << " I am in class A" << endl;
}
};
// Base class B
class B {
public:
void func() {
cout << " I am in class B" << endl;
}
};
// Derived class C
class C: public A, public B {
};
// Driver Code
int main() {
// Created an object of class C
C obj;
// Calling function func()
[Link]();
return 0;
}
Output:
[Link]: In function ‘int main()’:
[Link]:9: error: request for member ‘func’ is ambiguous
[Link]();
^
[Link]:10: note: candidates are: void B::func()
void func() {
^
[Link]:10: note: void A::func()
void func() {
^
In this example, derived class C inherited the two base classes A and B having
the same function name func(). When the object of class C is created and
called the function func() then the compiler gets confused that which base
class member function func() should be called.
Solution to Ambiguity:
To solve this ambiguity scope resolution operator is used denoted by ‘ :: ‘
Syntax:
[Link]::FunctionName();
Below is the program to show the concept of ambiguity resolution in multiple
inheritances.
● C++
// C++ program to resolve inheritance
// ambiguity
#include<iostream>
using namespace std;
// Base class A
class A {
public:
void func() {
cout << " I am in class A" << endl;
}
};
// Base class B
class B {
public:
void func() {
cout << " I am in class B" << endl;
}
};
// Derived class C
class C: public A, public B {
};
// Driver Code
int main() {
// Created an object of class C
C obj;
// Calling function func() in class A
obj.A::func();
// Calling function func() in class B
obj.B::func();
return 0;
}
Output
I am in class A
I am in class B
Why Java doesn't support Multiple Inheritance?
Java does not support multiple inheritance in classes to avoid complexity and
ambiguity, especially the "diamond problem":
Java disallows multiple inheritance to avoid the complexity and ambiguity
associated with it, particularly the "diamond problem," where a class inherits
from two classes that have a common ancestor, leading to conflicts in the
inheritance of methods.
Multiple Inheritance is a feature provided by OOPS, it helps us to create a class
that can inherit the properties from more than one parent. Some of the
programming languages like C++ can support multiple inheritance
but Java can't support multiple inheritance. This design choice is rooted in
various reasons including complexity management, ambiguity resolution, and
code management concerns.
Why Java doesn't Support Multiple Inheritance?
The major reason behind Java's lack of support for multiple inheritance lies in
its design philosophy of simplicity and clarity over complexity. By
disallowing Multiple Inheritance, Java aims to prevent the ambiguity and
complexities that can arise from having multiple parent classes.
Java class can be inherited from only one superclass using
the extends keyword. The single inheritance model ensures a clear
hierarchical structure where each class has a single direct superclass and it
can facilitate easier code maintenance and reduce the potential for conflicts.
Basic syntax:
class Parent {
// Parent class members and methods
}
class Child extends Parent {
// Child class members and methods
}
Diamond Problem
The diamond problem is the classic issue that can arise with multiple
inheritance. It occurs when the class inherits from the two classes that have a
common ancestor. This situation forms the diamond-shaped inheritance
hierarchy. It can lead to ambiguity in the method resolution.
Consider the scenario where class D inherits from classes B and C which both
inherits from Class A. This creates the diamond-shaped inheritance hierarchy.
In this scenario, both the classes B and C override the check() method
inherited from the class A. Now when the class D inherits from the B and C
then the conflict arises because class D doesn't know which check() method
to use.
Diamond problem with example methods code:
Java
class A {
void check() {
[Link]("Method foo() in class A");
}
}
class B extends A {
void check() {
[Link]("Method foo() in class B");
}
}
class C extends A {
void check() {
[Link]("Method foo() in class C");
}
}
class D extends B {
// Inherits foo() from class B
}
/*
class E extends B,C { // Error: Multiple inheritance not allowed in Java
// Some methods and members
}*/
public class Main {
public static void main(String[] args) {
D d = new D();
[Link]();
// Output: Method check() in class B
// Uncommenting the below code will result in a compilation error
/*
E e = new E();
[Link](); // Compilation Error: Reference to 'check()' is ambiguous
*/
}
}
Output
Method foo() in class B
Explanation of the above Program:
In the above example, class D can inherits from the class B and when the
calling check() on the instance of the class D then it calls the check() method
defined in class B. However, when defining the class E to inherit from the both
B and C then it results in compilation error due to the ambiguity of which check(
) method to use.
This ambiguity can highlights the diamond problem which arises from
potiential conflicts when the inheriting from the multiple classes with shared
anecestors. So Java doesn't allow the multiple inheritance helps to prevent
such issues and ensures more robust and predictable class hierarchy.
How to Avoid Multiple Inheritance in Java?
java can provides the alternative approaches to achieve the code reuse and
extensibility without resorting to the multiple inheritance.
1. Interfaces:
In Java, We can use Interfaces to define the contract for the set of behaviors
without implementing them. Classes can implement the multiple interfaces
and it can allowing them to inherit the method signatures from the multiple
sources.
Below is the Example to Avoid Multiple Inheritance in Java with Interface:
Java
// Java Program to Implement
// MultiLevel Inheritance
// Interface 1
interface InterfaceA {
void methodA();
}
// Interface 2
interface InterfaceB {
void methodB();
}
// Class
class MyClass implements InterfaceA, InterfaceB {
public void methodA() {
// Implementation of methodA
[Link]("A");
}
public void methodB() {
// Implementation of methodB
[Link]("B");
}
}
class Main{
public static void main(String args[]){
// Inheriting Properties from InterfaceA
InterfaceA x=new MyClass();
// Inheriting Properties from InterfaceB
InterfaceB y=new MyClass();
[Link]();
[Link]();
}
}
Output
A
B
2. Composition:
We can utilize the Composition where the objects are composed of the other
objects to achieve the code reuse without the complexities of the inheritance.
This can promotes the better encapsulation and flexibility of the code.
Below is the Example to Avoid Multiple Inheritance in Java with Composition:
Java
// Java Program to implement
// Java MultInheritance using Composition
import [Link].*;
// Class Engine(Parent)
class Engine {
void start() {
// Implementation of start method
[Link]("Engine starting.....");
}
}
// Class Car(Child 1)
class Car {
// Parent Class Object
Engine engine = new Engine();
void startCar() {
// Accessing Methods of Parent Class
[Link]("Car ... ");
[Link]();
}
}
// Class Bike(Child 3)
class Bike{
// Parent Class Object
Engine engine = new Engine();
void startBike() {
// Accessing Methods of Parent Class
[Link]("Bike ... ");
[Link]();
}
}
// Driver Class
class GFG {
// Main Method
public static void main (String[] args) {
// Creating Objects
Car x=new Car();
Bike y=new Bike();
// Accessing Methods in Class
[Link]();
[Link]();
}
}
Output
Car ... Engine starting.....
Bike ... Engine starting.....
By utilizing the interfaces and composition, Java developers can circumvent
the complexities of the multiple inheritance while still we can achieving the
code reuse, maintainability and flexibility in the projects.
S
Java doesn't support multiple inheritance aligns with its core prinicples of the
simplicity, reliability and maintainability empowering the developer can build
the concise class hierarchy. Java can provides the alternative mechanisms
such as the interfaces and composition to achieve code reuse and extensiblity
while avoiding the multiple inheritance.