Inheritance
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.
Inheritance is a feature or a process in which, new classes are created from the existing classes. The new class created is called “derived class” or “child class” and the existing class is known as the “base class” or “parent class”. The derived class now is said to be inherited from the base class.
When we say derived class inherits the base class, it means, the derived class inherits all the properties of the base class, without changing the properties of base class and may add new features to its own. These new features in the derived class will not affect the base class. The derived class is the specialized class for the base class.
Sub Class: The class that inherits properties from another class is called Subclass or Derived Class.
Super Class: The class whose properties are inherited by a subclass is called Base Class or Superclass.
Advantages of Inheritance:-
Code Reusability: One of the primary benefits of inheritance is code reuse. When a class inherits from another class, it automatically gains access to all the data members and member functions of the base class. This eliminates the need to rewrite code, leading to more efficient development and easier maintenance.
Polymorphism: Inheritance enables polymorphic behavior, allowing objects of derived classes to be treated as objects of their base class. This facilitates writing code that can operate on objects of multiple types, leading to more flexible and extensible designs.
Extensibility: Derived classes can add new functionality or modify existing behavior without modifying the base class. This promotes a modular design approach, where classes can be extended to accommodate new requirements without affecting the existing codebase.
Hierarchy Organization: Inheritance allows for the creation of class hierarchies, where classes are organized in a hierarchical structure based on their relationships. This helps in representing real-world relationships and modeling complex systems in a more natural and intuitive way.
Abstraction: Inheritance supports the concept of abstraction by allowing developers to define base classes that provide a common interface or behavior for a group of related classes. Derived classes then specialize or implement specific functionalities while inheriting common characteristics from their base class.
Encapsulation: Inheritance can be used in conjunction with other object-oriented programming principles such as encapsulation to create classes that hide their implementation details and expose only a well-defined interface. This improves modularity and reduces dependencies between different parts of a system.
Facilitates Method Overriding: Inheritance allows derived classes to override the behavior of base class methods, enabling customization and specialization. This is particularly useful for implementing variations of functionality in different subclasses while maintaining a consistent interface.
Eases Maintenance: By promoting code reuse, encapsulation, and modularity, inheritance can simplify the maintenance of software systems. Changes made to the base class can automatically propagate to all derived classes, ensuring consistency and reducing the likelihood of introducing bugs.
Base class and Derived class
A Base class, also known as a parent class or superclass, serves as the foundation for other classes. It defines common attributes and behaviors that are shared among its derived classes.
Syntax: For Base Class
class BaseClass {
// Data members
// Member functions
};
A Derived class, also known as a child class or subclass, inherits properties and behaviors from its base class. It can add new features or override existing ones.
Syntax: For derived Class
class DerivedClass : accessSpecifier BaseClass {
// Additional data members
// Additional member functions
};
Modes of Inheritance
There are 3 modes of Inheritance:
i) Public Mode: If we derive a subclass from a public base class. Then the public member of the base class will become public in the derived class and protected members of the base class will become protected in the derived class.
ii) Protected Mode: If we derive a subclass from a Protected base class. Then both public members and protected members of the base class will become protected in the derived class.
iii) Private Mode: If we derive a subclass from a Private base class. Then both public members and protected members of the base class will become Private in the derived class.
Types of Inheritance:
There are 5 types of Inheritance:
i) Single Inheritance
Single inheritance in C++ refers to the situation where a derived class inherits from only one base class. This is the most common form of inheritance and is widely used in object-oriented programming. In single inheritance, the derived class inherits all the properties and behaviors of the base class, allowing for code reuse and the creation of class hierarchies.
In single inheritance, each derived class has exactly one base class. The derived class inherits the non-private members (both data members and member functions) of the base class. This means that the derived class can access the public and protected members of the base class directly as if they were its own. Private members of the base class are not directly accessible by the derived class.
Syntax: For Single Inheritance
class BaseClass {
// Base class members
};
class DerivedClass : accessSpecifier BaseClass {
// Derived class members
};
Example: Single Inheritance
#include <iostream>
using namespace std;
class NepalEnotes {
public:
void display() {
cout << “This is NepalEnotes\n”;
}
};
class NexuCorner : public NepalEnotes {
public:
void Dhoni() {
cout << “Dhoni function in NexuCorner\n”;
}
};
int main() {
NexuCorner obj;
obj.display();
obj.Dhoni();
return 0;
}
ii) Multiple Inheritance
Multiple Inheritance is a feature of C++ where a class can inherit from two classes. The constructors of inherited classes are called in the same order in which they are inherited.
Syntax: Multiple Inheritance
class A
{
… .. …
};
class B
{
… .. …
};
class C: public A,public B
{
… … …
};
Example 1: Multiple Inheritance
#include<iostream>
using namespace std;
class A
{
public:
A() {
cout << “A’s constructor called” << endl; }
};
class B
{
public:B() {
cout << “B’s constructor called” << endl; }
};
class C: public B, public A // Note the order
{
public:
C() { cout << “C’s constructor called” << endl; }
};
int main()
{
C Obj;
return 0;
}
Example 2: Multiple Inheritance
#include <iostream>
using namespace std;
// Base class 1
class NepalEnotes {
public:
NepalEnotes() {
cout << “NepalEnotes constructor called” << endl;
}
void displayNepalEnotes() {
cout << “Displaying NepalEnotes” << endl;
}
};
// Base class 2
class Antoter {
public:
Antoter() {
cout << “Antoter constructor called” << endl;
}
void displayAntoter() {
cout << “Displaying Antoter” << endl;
}
};
// Derived class inheriting from NepalEnotes and Antoter
class NexuCorner : public NepalEnotes, public Antoter {
public:
NexuCorner() {
cout << “NexuCorner constructor called” << endl;
}
void displayNexuCorner() {
cout << “Displaying NexuCorner” << endl;
}
};
int main() {
// Creating an object of NexuCorner
NexuCorner obj;
// Accessing methods from each base class
obj.displayNepalEnotes();
obj.displayAntoter();
obj.displayNexuCorner();
return 0;
}
Ambiguity Error in Multiple Inheritance
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: Ambiguity Error
#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()
obj.func();
return 0;
}
Example: Solution of Ambiguity error in Multiple Inheritance
#include <iostream>
using namespace std;
// Base class 1
class NepalEnotes {
public:
void display() {
cout << “Displaying from NepalEnotes” << endl;
}
};
// Base class 2
class Antoter {
public:
void display() {
cout << “Displaying from Antoter” << endl;
}
};
// Derived class inheriting from NepalEnotes and Antoter
class NexuCorner : public NepalEnotes, public Antoter {
public:
// This function will cause ambiguity error
void display() {
cout << “Displaying from NexuCorner” << endl;
}
};
int main() {
NexuCorner obj;
// obj.display(); // This line would cause an ambiguity error
// We need to specify which display method to call
obj.NepalEnotes::display(); // Displaying from NepalEnotes
obj.Antoter::display(); // Displaying from Antoter
return 0;
}
iii) Multilevel Inheritance
It is the process of deriving a class from another derived class. When one class inherits another class it is further inherited by another class. It is known as multi-level inheritance.
Syntax:
class A // base class
{
………..
};
class B : access_specifier A // derived class
{
………..
} ;
class C : access_specifier B // derived from derived class B
{
………..
} ;
Example1 : Multilevel Inheritance
#include<iostream>
using namespace std;
// single base class
class A {
public:
int a;
void get_A_data()
{
cout << “Enter value of a: “;
cin >> a;
}
};
// derived class from base class
class B : public A {
public:
int b;
void get_B_data()
{
cout << “Enter value of b: “;
cin >> b;
}
};
// derived from class derive1
class C : public B {
private:
int c;
public:
void get_C_data()
{
cout << “Enter value of c: “;
cin >> c;
}
// function to print sum
void sum()
{
int ans = a + b + c;
cout << “sum: ” << ans;
}
};
int main()
{
// object of sub class
C obj;
obj.get_A_data();
obj.get_B_data();
obj.get_C_data();
obj.sum();
return 0;
}
Example 2: Multilevel Inheritance
#include <iostream>
using namespace std;
// Base class
class NepalEnotes {
public:
NepalEnotes() {
cout << “NepalEnotes constructor called” << endl;
}
void displayNepalEnotes() {
cout << “Displaying NepalEnotes” << endl;
}
};
// Derived class 1
class Nexus : public NepalEnotes {
public:
Nexus() {
cout << “Nexus constructor called” << endl;
}
void displayNexus() {
cout << “Displaying Nexus” << endl;
}
};
// Derived class 2
class NexuCorner : public Nexus {
public:
NexuCorner() {
cout << “NexuCorner constructor called” << endl;
}
void displayNexuCorner() {
cout << “Displaying NexuCorner” << endl;
}
};
int main() {
// Creating an object of NexuCorner
NexuCorner obj;
// Accessing methods from all levels of inheritance
obj.displayNepalEnotes();
obj.displayNexus();
obj.displayNexuCorner();
return 0;
}
iv) Hierarchical Inheritance
In Hierarchical inheritance, more than one sub-class inherits the property of a single base class. There is one base class and multiple derived classes. Several other classes inherit the derived classes as well. Hierarchical structures thus form a tree-like structure.
The below diagram shows, Class A is a Base class, B is a subclass inherited from class A, and C is a subclass it also inherits from class A.
Syntax: For Hierarchical Inheritance
Class A
{
…………
};
Class B: access_specifier A
{
………
};
Class C: access_specifier A
{
………….
};
Example 1: Hierarchial Inheritance
// C++ program for Hierarchical Inheritance
#include<iostream>
using namespace std;
class A //superclass A
{
public:
void show_A() {
cout<<“class A”<<endl;
}
};
class B : public A //subclass B
{
public:
void show_B() {
cout<<“class B”<<endl;
}
};
class C : public A //subclass C
{
public:
void show_C() {
cout<<“class C”<<endl;
}
};
int main() {
B b; // b is object of class B
cout<<“calling from B: “<<endl;
b.show_B();
b.show_A();
C c; // c is object of class C
cout<<“calling from C: “<<endl;
c.show_C();
c.show_A();
return 0;
}
Example 2: Hierarchial Inheritance
#include <iostream>
using namespace std;
// Base class
class NepalEnotes {
public:
NepalEnotes() {
cout << “NepalEnotes constructor called” << endl;
}
void displayNepalEnotes() {
cout << “Displaying NepalEnotes” << endl;
}
};
// Derived class 1
class Nexus : public NepalEnotes {
public:
Nexus() {
cout << “Nexus constructor called” << endl;
}
void displayNexus() {
cout << “Displaying Nexus” << endl;
}
};
// Derived class 2
class NexuCorner : public NepalEnotes {
public:
NexuCorner() {
cout << “NexuCorner constructor called” << endl;
}
void displayNexuCorner() {
cout << “Displaying NexuCorner” << endl;
}
};
int main() {
// Creating objects of Nexus and NexuCorner
Nexus obj1;
NexuCorner obj2;
// Accessing methods from their respective classes
obj1.displayNepalEnotes(); // Accessing from Nexus
obj1.displayNexus();
obj2.displayNepalEnotes(); // Accessing from NexuCorner
obj2.displayNexuCorner();
return 0;
}
v) Hybrid Inheritance
Hybrid inheritance in C++ is a combination of multiple types of inheritance, such as single, multiple, multilevel, and hierarchical inheritance. It allows classes to inherit from multiple base classes using a combination of these inheritance types.
There are different ways hybrid inheritance can be achieved:
Single and Multiple Inheritance: A class can inherit from one base class using single inheritance and from multiple base classes using multiple inheritance.
Multilevel and Multiple Inheritance: A class can inherit from a base class, and then another class can inherit from this derived class, forming a multilevel inheritance. Additionally, this derived class can inherit from multiple base classes, leading to multiple inheritance.
Hierarchical and Multiple Inheritance: Multiple derived classes can inherit from a common base class, forming a hierarchical structure, and these derived classes can also inherit from other base classes, resulting in multiple inheritance.
Note: Hybrid inheritance offers flexibility in designing class hierarchies, allowing for greater code reuse and organization. However, it can also introduce complexities, such as ambiguity issues and the diamond problem, which need to be carefully managed using techniques like virtual inheritance and explicit scope resolution.
Example: Hybrid using Single and Multiple Inheritance
#include <iostream>
using namespace std;
// Base class
class NepalEnotes {
public:
NepalEnotes() {
cout << “NepalEnotes constructor called” << endl;
}
void displayNepalEnotes() {
cout << “Displaying NepalEnotes” << endl;
}
};
// Derived class 1 (Single Inheritance)
class Nexus : public NepalEnotes {
public:
Nexus() {
cout << “Nexus constructor called” << endl;
}
void displayNexus() {
cout << “Displaying Nexus” << endl;
}
};
// Derived class 2 (Multiple Inheritance)
class NexuCorner : public NepalEnotes, public Nexus {
public:
NexuCorner() {
cout << “NexuCorner constructor called” << endl;
}
void displayNexuCorner() {
cout << “Displaying NexuCorner” << endl;
}
};
int main() {
// Creating an object of NexuCorner
NexuCorner obj;
// Accessing methods from all levels of inheritance
obj.displayNepalEnotes(); // Accessing from NepalEnotes
obj.displayNexus(); // Accessing from Nexus
obj.displayNexuCorner(); // Accessing from NexuCorner
return 0;
}
Example: Hybrid Inheritance using Multiple and Multilevel Inheritance
#include <iostream>
using namespace std;
// Base class
class NepalEnotes {
public:
NepalEnotes() {
cout << “NepalEnotes constructor called” << endl;
}
void displayNepalEnotes() {
cout << “Displaying NepalEnotes” << endl;
}
};
// Derived class 1 (Multilevel Inheritance)
class Nexus : public NepalEnotes {
public:
Nexus() {
cout << “Nexus constructor called” << endl;
}
void displayNexus() {
cout << “Displaying Nexus” << endl;
}
};
// Derived class 2 (Multiple Inheritance)
class NexuCorner : public NepalEnotes, public Nexus {
public:
NexuCorner() {
cout << “NexuCorner constructor called” << endl;
}
void displayNexuCorner() {
cout << “Displaying NexuCorner” << endl;
}
};
int main() {
// Creating an object of NexuCorner
NexuCorner obj;
// Accessing methods from all levels of inheritance
obj.displayNepalEnotes(); // Accessing from NepalEnotes
obj.displayNexus(); // Accessing from Nexus
obj.displayNexuCorner(); // Accessing from NexuCorner
return 0;
}
Example: Hybrid Inheritance using Multiple and Hierarchial Inheritance
#include <iostream>
using namespace std;
// Base class
class NepalEnotes {
public:
NepalEnotes() {
cout << “NepalEnotes constructor called” << endl;
}
void displayNepalEnotes() {
cout << “Displaying NepalEnotes” << endl;
}
};
// Derived class 1 (Hierarchical Inheritance)
class Nexus : public NepalEnotes {
public:
Nexus() {
cout << “Nexus constructor called” << endl;
}
void displayNexus() {
cout << “Displaying Nexus” << endl;
}
};
// Derived class 2 (Multiple Inheritance)
class NexuCorner : public NepalEnotes, public Nexus {
public:
NexuCorner() {
cout << “NexuCorner constructor called” << endl;
}
void displayNexuCorner() {
cout << “Displaying NexuCorner” << endl;
}
};
int main() {
// Creating an object of NexuCorner
NexuCorner obj;
// Accessing methods from all levels of inheritance
obj.displayNepalEnotes(); // Accessing from NepalEnotes
obj.displayNexus(); // Accessing from Nexus
obj.displayNexuCorner(); // Accessing from NexuCorner
return 0;
}