Types of Inheritance

Inheritance allows one class (called the derived class) to acquire the properties and behaviors (data members and member functions) of another class (called the base class). This promotes code reuse and establishes relationships between classes. C++ supports different types of inheritance to represent various relationship between classes.

Here are the five main types of inheritance in C++:

  1. Single Inheritance
  2. Multiple Inheritance
  3. Multilevel Inheritance
  4. Hierarchical Inheritance
  5. Hybrid Inheritance

Types of Inheritance

1️⃣ Single Inheritance

In single inheritance, a class inherits from only one base class. This is the simplest form of inheritance and represents a one-to-one relationship between classes. The derived class extends the functionality of a single base class.

Syntax:

class Base {
    // Base class members
};

class Derived : public Base {
    // Derived class members
};
Example:
#include <iostream>
using namespace std;

class Animal {
public:
    void eat() {
        cout << "Eating..." << endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        cout << "Barking..." << endl;
    }
};

int main() {
    Dog d;
    d.eat();   // Inherited from Animal class
    d.bark();  // Defined in Dog class
    return 0;
}

In this example:

  • The Dog class inherits from the Animal class.
  • The Dog class can use both eat() (inherited) and bark() (defined in Dog).

2️⃣ Multiple Inheritance

In multiple inheritance, a class inherits from more than one base class. This allows the derived class to combine functionalities from multiple base classes, leading to a many-to-one relationship between classes.

Syntax:

class Base1 {
    // Base class 1 members
};

class Base2 {
    // Base class 2 members
};

class Derived : public Base1, public Base2 {
    // Derived class members
};
Example:
#include <iostream>
using namespace std;

class Father {
public:
    void height() {
        cout << "Father is tall." << endl;
    }
};

class Mother {
public:
    void skinColor() {
        cout << "Mother has fair skin." << endl;
    }
};

class Child : public Father, public Mother {
public:
    void traits() {
        height();
        skinColor();
    }
};

int main() {
    Child c;
    c.traits();
    return 0;
}

In this example:

  • The Child class inherits from both Father and Mother.
  • The Child class can access members from both base classes.

Considerations:

  • Ambiguity: Multiple inheritance can lead to ambiguity when the same member is inherited from more than one base class. This can be resolved using the scope resolution operator or virtual inheritance.

3️⃣ Multilevel Inheritance

In multilevel inheritance, a class is derived from another derived class. This creates a chain of inheritance where a class inherits from a base class, and another class inherits from the derived class. This forms a one-to-one-to-one relationship.

Syntax:

class Base {
    // Base class members
};

class Intermediate : public Base {
    // Intermediate derived class members
};

class Final : public Intermediate {
    // Final derived class members
};
Example:
#include <iostream>
using namespace std;

class LivingBeing {
public:
    void breathe() {
        cout << "Breathing..." << endl;
    }
};

class Animal : public LivingBeing {
public:
    void eat() {
        cout << "Eating..." << endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        cout << "Barking..." << endl;
    }
};

int main() {
    Dog d;
    d.breathe();  // Inherited from LivingBeing
    d.eat();      // Inherited from Animal
    d.bark();     // Defined in Dog
    return 0;
}

In this example:

  • The Dog class inherits from Animal, which in turn inherits from LivingBeing.
  • The Dog class inherits members from both Animal and LivingBeing.

4️⃣ Hierarchical Inheritance

In hierarchical inheritance, multiple classes inherit from the same base class. This creates a one-to-many relationship between the base class and derived classes. Hierarchical inheritance is useful when different derived classes share common properties of a base class but extend it in different ways.

Syntax:

class Base {
    // Base class members
};

class Derived1 : public Base {
    // Derived class 1 members
};

class Derived2 : public Base {
    // Derived class 2 members
};
Example:
#include <iostream>
using namespace std;

class Animal {
public:
    void eat() {
        cout << "Eating..." << endl;
    }
};

class Dog : public Animal {
public:
    void bark() {
        cout << "Barking..." << endl;
    }
};

class Cat : public Animal {
public:
    void meow() {
        cout << "Meowing..." << endl;
    }
};

int main() {
    Dog d;
    Cat c;
    d.eat();   // Inherited from Animal
    d.bark();  // Defined in Dog

    c.eat();   // Inherited from Animal
    c.meow();  // Defined in Cat

    return 0;
}

In this example:

  • Both Dog and Cat classes inherit from the Animal class.
  • Both classes share the eat() method but have their own unique behaviors (bark() for Dog and meow() for Cat).

5️⃣ Hybrid Inheritance

Hybrid inheritance is a combination of two or more types of inheritance (e.g., single, multiple, multilevel, or hierarchical inheritance). Hybrid inheritance can lead to complex relationships, especially when multiple inheritance is involved. It may also involve virtual inheritance to avoid ambiguity when multiple derived classes inherit from the same base class.

Syntax:

class Base {
    // Base class members
};

class Derived1 : public Base {
    // Derived class 1 members
};

class Derived2 : public Base {
    // Derived class 2 members
};

class Final : public Derived1, public Derived2 {
    // Final derived class members
};
Example:
#include <iostream>
using namespace std;

class Animal {
public:
    void eat() {
        cout << "Eating..." << endl;
    }
};

class Mammal : public Animal {
public:
    void giveBirth() {
        cout << "Giving birth..." << endl;
    }
};

class Bird : public Animal {
public:
    void layEggs() {
        cout << "Laying eggs..." << endl;
    }
};

class Bat : public Mammal, public Bird {
public:
    void fly() {
        cout << "Flying..." << endl;
    }
};

int main() {
    Bat b;
    b.eat();       // Ambiguity: resolved using scope resolution or virtual inheritance
    b.giveBirth(); // Inherited from Mammal
    b.fly();       // Defined in Bat

    return 0;
}

In this example:

  • The Bat class inherits from both Mammal and Bird, which both inherit from Animal.
  • Ambiguity arises for the eat() method, as it is inherited from both Mammal and Bird. This can be resolved using virtual inheritance or scope resolution.

Virtual Inheritance

In cases where multiple inheritance leads to ambiguity (such as the diamond problem), virtual inheritance can be used to ensure that only one instance of a base class is inherited, even if multiple derived classes share the same base class.

Diamond Problem:

#include <iostream>
using namespace std;

class Base {
public:
    Base() { cout << "Base class constructor" << endl; }
};

class Derived1 : public Base {
public:
    Derived1() { cout << "Derived1 class constructor" << endl; }
};

class Derived2 : public Base {
public:
    Derived2() { cout << "Derived2 class constructor" << endl; }
};

class Final : public Derived1, public Derived2 {
public:
    Final() { cout << "Final class constructor" << endl; }
};

int main() {
    Final f;
    return 0;
}

Output:
Base class constructor
Derived1 class constructor
Base class constructor
Derived2 class constructor
Final class constructor

Solution:

class Base {
public:
    Base() { cout << "Base class constructor" << endl; }
};

class Derived1 : virtual public Base {
public:
    Derived1() { cout << "Derived1 class constructor" << endl; }
};

class Derived2 : virtual public Base {
public:
    Derived2() { cout << "Derived2 class constructor" << endl; }
};

class Final : public Derived1, public Derived2 {
public:
    Final() { cout << "Final class constructor" << endl; }
};

int main() {
    Final f;
    return 0;
}
Output:
Base class constructor
Derived1 class constructor
Derived2 class constructor
Final class constructor

In this case:

  • The Base class constructor is called only once, even though both Derived1 and Derived2 inherit from it. This is achieved using virtual inheritance.