Inheritance

Inheritance is a fundamental concept in object-oriented programming (OOP) that allows a class to inherit properties and behavior from another class. In C++, inheritance enables the creation of hierarchical relationships between classes, promoting code reuse and enhancing code organization.

Basic Inheritance

In basic inheritance, a derived class (also known as a subclass or child class) inherits properties and methods from a base class (also known as a superclass or parent class). This means that the derived class can access the members of the base class.

				
					#include <iostream>

// Base class
class Animal {
public:
    void eat() {
        std::cout << "Animal is eating." << std::endl;
    }
};

// Derived class
class Dog : public Animal {
public:
    void bark() {
        std::cout << "Dog is barking." << std::endl;
    }
};

int main() {
    Dog dog;
    dog.eat();  // Accessing base class method
    dog.bark(); // Accessing derived class method
    return 0;
}

				
			
				
					// output //
Animal is eating.
Dog is barking.

				
			

Explanation:

In this example, we have a base class Animal with a method eat(). We also have a derived class Dog which inherits from Animal. The Dog class has its own method bark(). In the main() function, we create an instance of Dog and demonstrate accessing both base class and derived class methods.

Types of Inheritance

Single Inheritance

  • In single inheritance, a derived class inherits from only one base class.
  • This is the most common form of inheritance and forms a linear relationship between classes.
  • It promotes code reusability by allowing derived classes to inherit properties and behaviors from a single base class.
				
					#include <iostream>

// Base class
class Shape {
public:
    void draw() {
        std::cout << "Drawing shape." << std::endl;
    }
};

// Derived class
class Circle : public Shape {
public:
    void drawCircle() {
        std::cout << "Drawing circle." << std::endl;
    }
};

int main() {
    Circle circle;
    circle.draw();      // Accessing base class method
    circle.drawCircle(); // Accessing derived class method
    return 0;
}

				
			
				
					// output //
Drawing shape.
Drawing circle.

				
			

Explanation:

In this example, the Circle class inherits publicly from the Shape class, demonstrating single inheritance. The Circle class can access the draw() method from the Shape class and define its own methods.

Multiple Inheritance

  • In multiple inheritance, a derived class inherits from multiple base classes.
  • This allows a class to combine features and behaviors from multiple sources, potentially from unrelated classes.
  • It offers flexibility but can lead to ambiguity and complexity, especially if the same member is inherited from multiple base classes.
				
					#include <iostream>

// Base class 1
class Animal {
public:
    void breathe() {
        std::cout << "Animal breathes." << std::endl;
    }
};

// Base class 2
class Mammal {
public:
    void eat() {
        std::cout << "Mammal eats." << std::endl;
    }
};

// Derived class inheriting from multiple base classes
class Dog : public Animal, public Mammal {
public:
    void bark() {
        std::cout << "Dog barks." << std::endl;
    }
};

int main() {
    Dog dog;
    dog.breathe(); // Accessing method from Animal
    dog.eat();     // Accessing method from Mammal
    dog.bark();    // Accessing method from Dog
    return 0;
}

				
			
				
					// output //
Animal breathes.
Mammal eats.
Dog barks.

				
			

Explanation:

In this example, the Dog class inherits from both the Animal and Mammal classes, demonstrating multiple inheritance. The Dog class can access methods from both base classes along with its own methods.

Multilevel Inheritance

  • In multilevel inheritance, a derived class inherits from another derived class.
  • This forms a hierarchy of classes, where each subsequent class inherits from its immediate parent.
  • It allows for the creation of a deeper hierarchy of related classes, each building upon the functionality of the previous one.
				
					#include <iostream>

// Base class
class Vehicle {
public:
    void start() {
        std::cout << "Vehicle started." << std::endl;
    }
};

// Derived class
class Car : public Vehicle {
public:
    void drive() {
        std::cout << "Car is being driven." << std::endl;
    }
};

// Further derived class
class Sedan : public Car {
public:
    void park() {
        std::cout << "Sedan is parked." << std::endl;
    }
};

int main() {
    Sedan sedan;
    sedan.start(); // Accessing method from Vehicle
    sedan.drive(); // Accessing method from Car
    sedan.park();  // Accessing method from Sedan
    return 0;
}

				
			
				
					// output //
Vehicle started.
Car is being driven.
Sedan is parked.

				
			

Explanation:

In this example, the Sedan class inherits from the Car class, which in turn inherits from the Vehicle class, demonstrating multilevel inheritance. The Sedan class can access methods from both Car and Vehicle classes.

Hierarchical Inheritance

  • In hierarchical inheritance, multiple derived classes inherit from a single base class.
  • This allows for the creation of a branching hierarchy, where different classes inherit from a common ancestor.
  • It promotes code organization and reuse by sharing common functionality among multiple derived classes.
				
					#include <iostream>

// Base class
class Shape {
public:
    void draw() {
        std::cout << "Drawing shape." << std::endl;
    }
};

// Derived classes
class Circle : public Shape {
public:
    void drawCircle() {
        std::cout << "Drawing circle." << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void drawRectangle() {
        std::cout << "Drawing rectangle." << std::endl;
    }
};

int main() {
    Circle circle;
    circle.draw();        // Accessing method from Shape
    circle.drawCircle();  // Accessing method from Circle

    Rectangle rectangle;
    rectangle.draw();           // Accessing method from Shape
    rectangle.drawRectangle();  // Accessing method from Rectangle

    return 0;
}

				
			
				
					// output //
Drawing shape.
Drawing circle.
Drawing shape.
Drawing rectangle.

				
			

Explanation:

In this example, both the Circle and Rectangle classes inherit from the Shape class, demonstrating hierarchical inheritance. Each derived class specializes in drawing a specific shape while sharing the common drawing functionality from the base class.

Hybrid Inheritance

Hybrid inheritance is a combination of multiple inheritance and multilevel inheritance. It involves a mix of inheriting from multiple base classes and deriving classes from other derived classes. This inheritance model provides a high level of flexibility but can also introduce complexity and potential ambiguity.

				
					#include <iostream>

// Base class 1
class Animal {
public:
    void breathe() {
        std::cout << "Animal breathes." << std::endl;
    }
};

// Base class 2
class Vehicle {
public:
    void start() {
        std::cout << "Vehicle started." << std::endl;
    }
};

// Intermediate derived class
class Mammal : public Animal {
public:
    void eat() {
        std::cout << "Mammal eats." << std::endl;
    }
};

// Derived class inheriting from multiple base classes and intermediate derived class
class Dog : public Mammal, public Vehicle {
public:
    void bark() {
        std::cout << "Dog barks." << std::endl;
    }
};

int main() {
    Dog dog;
    dog.breathe(); // Accessing method from Animal (through Mammal)
    dog.start();   // Accessing method from Vehicle
    dog.eat();     // Accessing method from Mammal
    dog.bark();    // Accessing method from Dog
    return 0;
}

				
			
				
					// output //
Animal breathes.
Vehicle started.
Mammal eats.
Dog barks.

				
			

Explanation:

In this example, the Dog class inherits from both the Mammal class (which in turn inherits from the Animal class) and the Vehicle class, demonstrating hybrid inheritance. The Dog class can access methods from multiple base classes and an intermediate derived class.

Access Specifiers in Inheritance

Access specifiers play a crucial role in controlling the visibility of base class members in the derived class when using inheritance in C++. There are three access specifiers: public, protected, and private. Each specifier determines how the members of the base class are accessible in the derived class.

Public Inheritance

  • When a derived class inherits publicly from a base class, public members of the base class remain public in the derived class.
  • Protected members of the base class remain protected in the derived class.
  • Private members of the base class are not accessible in the derived class.
				
					#include <iostream>

// Base class
class Base {
public:
    int publicMember;
protected:
    int protectedMember;
private:
    int privateMember;
};

// Derived class
class Derived : public Base {
public:
    void accessBaseMembers() {
        publicMember = 10;     // Accessible
        protectedMember = 20;  // Accessible
        // privateMember = 30; // Not accessible
    }
};

int main() {
    Derived derivedObj;
    derivedObj.accessBaseMembers();
    return 0;
}

				
			

Explanation:

In this example, the Derived class inherits publicly from the Base class. The publicMember and protectedMember of the Base class are accessible within the Derived class. However, the privateMember of the Base class is not accessible directly in the Derived class.

Protected Inheritance

  • When a derived class inherits protectedly from a base class, public and protected members of the base class become protected in the derived class.
  • Private members of the base class are not accessible in the derived class.
				
					#include <iostream>

// Base class
class Base {
public:
    int publicMember;
protected:
    int protectedMember;
private:
    int privateMember;
};

// Derived class
class Derived : protected Base {
public:
    void accessBaseMembers() {
        publicMember = 10;     // Accessible
        protectedMember = 20;  // Accessible
        // privateMember = 30; // Not accessible
    }
};

int main() {
    Derived derivedObj;
    derivedObj.accessBaseMembers();
    return 0;
}

				
			

Explanation:

In this example, the Derived class inherits protectedly from the Base class. Both publicMember and protectedMember of the Base class become protected members of the Derived class. The privateMember of the Base class remains inaccessible in the Derived class.

Private Inheritance

  • When a derived class inherits privately from a base class, all members of the base class become private in the derived class.
  • Neither public nor protected members of the base class are directly accessible in the derived class.
				
					#include <iostream>

// Base class
class Base {
public:
    int publicMember;
protected:
    int protectedMember;
private:
    int privateMember;
};

// Derived class
class Derived : private Base {
public:
    void accessBaseMembers() {
        // publicMember = 10;     // Not accessible
        // protectedMember = 20;  // Not accessible
        // privateMember = 30;    // Not accessible
    }
};

int main() {
    Derived derivedObj;
    // derivedObj.accessBaseMembers(); // Not accessible
    return 0;
}

				
			

Explanation:

In this example, the Derived class inherits privately from the Base class. All members of the Base class become private in the Derived class, meaning they are not directly accessible outside the class.

Advanced Inheritance Concepts

Beyond basic inheritance, C++ offers several advanced concepts to enhance the flexibility and functionality of inheritance:

  1. Virtual Inheritance: When a class inherits virtually from a base class, it ensures that only one instance of the base class exists in the derived class hierarchy, resolving issues such as the “diamond problem” in multiple inheritance.

  2. Abstract Base Classes: Abstract classes are classes that cannot be instantiated and contain one or more pure virtual functions. They serve as interfaces, defining a common protocol for derived classes to implement.

  3. Interface Inheritance: C++ does not have a native interface keyword like some other languages, but interface-like behavior can be achieved through abstract base classes containing only pure virtual functions.

  4. Final Keyword: In C++11 and later, the final keyword can be used to prevent a class from being inherited further or a virtual function from being overridden in derived classes.

Diamond Problem ?

The “diamond problem” is a common issue that arises in multiple inheritance scenarios, particularly in languages like C++ that support it. It occurs when a class inherits from two or more classes that have a common ancestor. This common ancestor can lead to ambiguity in the derived class due to the presence of duplicate inherited members.

				
					#include <iostream>

// Base class
class Animal {
public:
    void breathe() {
        std::cout << "Animal breathes." << std::endl;
    }
};

// Intermediate base class 1
class Mammal : public Animal {
public:
    void eat() {
        std::cout << "Mammal eats." << std::endl;
    }
};

// Intermediate base class 2
class Bird : public Animal {
public:
    void fly() {
        std::cout << "Bird flies." << std::endl;
    }
};

// Derived class inheriting from multiple base classes
class Bat : public Mammal, public Bird {
public:
    void nocturnal() {
        std::cout << "Bat is nocturnal." << std::endl;
    }
};

int main() {
    Bat bat;
    bat.breathe(); // Accessing method from which base class? Ambiguity!
    return 0;
}

				
			

In this example, the Bat class inherits from both the Mammal class and the Bird class, which both inherit from the Animal class. When we create an instance of the Bat class and try to call the breathe() method, it’s ambiguous to the compiler which breathe() method it should call, from the Mammal class or the Bird class.

In Above example this Animal class comes two times in Bat , For example 

Memory layout 

Animal – breathe()

Mammal – breathe (), eat()

Bird – breathe(), fly()

Bat – breathe() , eat() , breathe(), fly() 

So here two times breathe() function got duplicated so now compiler is confused which function to be called.

Resolution: Virtual Inheritance 

To resolve the diamond problem, C++ provides a concept called virtual inheritance. By using virtual inheritance, we can ensure that there is only one instance of the common base class in the hierarchy, avoiding the duplication of inherited members.

				
					#include <iostream>

// Base class with virtual inheritance
class Animal {
public:
    void breathe() {
        std::cout << "Animal breathes." << std::endl;
    }
};

// Intermediate base classes with virtual inheritance
class Mammal : virtual public Animal {
public:
    void eat() {
        std::cout << "Mammal eats." << std::endl;
    }
};

class Bird : virtual public Animal {
public:
    void fly() {
        std::cout << "Bird flies." << std::endl;
    }
};

// Derived class inheriting from multiple base classes with virtual inheritance
class Bat : public Mammal, public Bird {
public:
    void nocturnal() {
        std::cout << "Bat is nocturnal." << std::endl;
    }
};

int main() {
    Bat bat;
    bat.breathe(); // Calls the breathe() method from the common ancestor Animal
    return 0;
}

				
			
				
					// output //
Animal breathes.

				
			

Explanation:

In this modified example, we use virtual inheritance for both the Mammal and Bird classes. This ensures that there is only one instance of the Animal class in the hierarchy, resolving the ambiguity. Now, when we call the breathe() method on an instance of the Bat class, it calls the breathe() method from the common ancestor Animal class.

More about Virtual Inheritance

Virtual inheritance is a mechanism provided by C++ to resolve the “diamond problem” that occurs in multiple inheritance scenarios. The diamond problem arises when a class inherits from two or more classes that have a common ancestor. This common ancestor can lead to ambiguity in the derived class due to the presence of duplicate inherited members.

Virtual inheritance allows us to ensure that there is only one instance of a common base class in the inheritance hierarchy, thus resolving the ambiguity and preventing issues such as duplicate member inheritance.

Declaration of Virtual Inheritance: To declare virtual inheritance, we use the virtual keyword before the base class name in the derived class declaration.

				
					class Derived : virtual public Base {
    // Derived class definition
};

				
			

In this example, Derived virtually inherits from Base.

Single Instance of the Base Class: With virtual inheritance, there is only one instance of the virtual base class in the entire inheritance hierarchy, regardless of how many times it appears in the inheritance graph.

Resolving Ambiguity: When a derived class has multiple paths to access the same base class (e.g., through multiple inheritance), the compiler resolves any potential ambiguity by ensuring that all paths lead to the single instance of the virtual base class.

Construction and Destruction Order: Virtual inheritance affects the construction and destruction order of objects. The virtual base class is initialized by the most derived class in the inheritance hierarchy and is constructed before any non-virtual base classes. Similarly, the virtual base class is destroyed after all other non-virtual base classes.

				
					class Base {
    // Base class definition
};

class Derived1 : virtual public Base {
    // Derived1 class definition
};

class Derived2 : virtual public Base {
    // Derived2 class definition
};

class MostDerived : public Derived1, public Derived2 {
    // MostDerived class definition
};

				
			

In this example, Base is constructed before Derived1 and Derived2 in the MostDerived class constructor.

Use Cases: Virtual inheritance is typically used in situations where we have a diamond-shaped inheritance hierarchy and want to avoid duplication of inherited members and resolve ambiguity. It is commonly employed in design patterns such as the “Composite” and “Visitor” patterns.

Inheritance is a versatile mechanism in C++ that allows for the creation of complex class hierarchies, enabling code reuse, modularity, and polymorphism. By understanding both the basic and advanced concepts of inheritance, developers can design elegant and maintainable software solutions that leverage the full power of object-oriented programming. Happy coding !❤️

Table of Contents

Contact here

Copyright © 2025 Diginode

Made with ❤️ in India