Introduction to C++ Inheritance

Inheritance is one of the core features of Object-Oriented Programming (OOP) in C++. It allows a class (called the derived class) to inherit the properties and behaviors (i.e., data members and member functions) of another class (called the base class).

In simpler terms:

  • A base class is similar to a parent class.
  • A derived class is like a child class that inherits the properties and behaviors of the parent class, but it can also include its own unique features.

Syntax of Inheritance

In C++, inheritance is achieved using the : symbol, followed by the inheritance type (public, protected, or private).

class Derived: access_specifier Base {
// Derived class implementation
};

Where:

  • Base: The class that is being inherited, also called parent class.
  • Derived: The new class that inherits the base class, also called the child class.
  • Access_specifier: Defines the level of access to base class members in the derived class. it can be public, protected, or private.

Types of Inheritance In C++

C++ supports various types of inheritance. These types are based on how the derived class relates to the base class.

1. Single Inheritance

Single inheritance is when a derived class inherits from only one base class. The syntax of single inheritance is given below,

Syntax:

class Base {
// Base class members
};class Derived : public Base {
// Derived class inherits from Base
};

Example of Single inheritance:

#include <iostream>
using namespace std;// Base Class
class Animal {
public:
// A member function of the base class
void eat() {
cout << “This animal eats food.” << endl;
}
};

// Derived Class inheriting from Animal
class Dog : public Animal {
public:
// A member function of the derived class
void bark() {
cout << “The dog barks.” << endl;
}
};

int main() {
// Creating an object of the derived class
Dog dog;

// Calling function from the base class
dog.eat(); // Inherited from Animal

// Calling function from the derived class
dog.bark(); // Defined in Dog

return 0;
}

Output:

This animal eats food.
The dog barks.

2. Multiple Inheritance

Multiple inheritance occurs when a derived class inherits from more than one base class.

Syntax of Multiple Inheritance

class Base1 {
// Base1 class members
};class Base2 {
// Base2 class members
};

class Derived : public Base1, public Base2 {
// Derived class inherits from Base1 and Base2
};

Example of Multiple Inheritance

#include <iostream>
using namespace std;// Base Class 1
class Animal {
public:
// A member function of the first base class
void eat() {
cout << “This animal eats food.” << endl;
}
};

// Base Class 2
class Mammal {
public:
// A member function of the second base class
void sleep() {
cout << “This mammal is sleeping.” << endl;
}
};

// Derived Class inheriting from both Animal and Mammal
class Dog : public Animal, public Mammal {
public:
// A member function of the derived class
void bark() {
cout << “The dog barks.” << endl;
}
};

int main() {
// Creating an object of the derived class
Dog dog;

// Calling function from the first base class
dog.eat(); // Inherited from Animal

// Calling function from the second base class
dog.sleep(); // Inherited from Mammal

// Calling function from the derived class
dog.bark(); // Defined in Dog

return 0;
}

Output:

This animal eats food.
This mammal is sleeping.
The dog barks.

3. Multilevel Inheritance

Multilevel inheritance occurs when a class derives from another class, which in turn is derived from another class.

class Base {
// Base class members
};class Intermediate : public Base {
// Intermediate class inherits from Base
};

class Derived : public Intermediate {
// Derived class inherits from Intermediate (and also from Base)
};

4. Hierarchical Inheritance

In hierarchical inheritance, multiple derived classes inherit from a single base class.

class Base {
// Base class members
};class Derived1 : public Base {
// Derived1 class inherits from Base
};

class Derived2 : public Base {
// Derived2 class inherits from Base
};

Example of Hierarchical Inheritance

#include <iostream>
using namespace std;

// Base class
class Animal {
public:
void speak() {
cout << “Animal makes a sound.” << endl;
}
};

// Derived class 1
class Dog : public Animal {
public:
void speak() {
cout << “Dog barks.” << endl;
}
};

// Derived class 2
class Cat : public Animal {
public:
void speak() {
cout << “Cat meows.” << endl;
}
};

int main() {
Dog dog;
Cat cat;

// Calling speak method of derived classes
dog.speak(); // Output: Dog barks.
cat.speak(); // Output: Cat meows.

return 0;
}

Output:

Dog barks.
Cat meows.

Explanation: Dog and Cat are derived classes that inherit from the Animal class. Both classes override the speak() method to provide their own specific sounds.

5. Hybrid Inheritance

Hybrid inheritance is a combination of two or more types of inheritance. This can lead to complexities such as the diamond problem, which requires careful handling.

class Base {
// Base class members
};class Intermediate1 : public Base {
// Intermediate1 inherits from Base
};

class Intermediate2 : public Base {
// Intermediate2 inherits from Base
};

class Derived : public Intermediate1, public Intermediate2 {
// Derived class inherits from both Intermediate1 and Intermediate2
};

Access Specifiers in Inheritance

The access specifier used in the derived class inheritance determines how the members of the base class are inherited. The access specifiers available in inheritance are:

  • Public Inheritance (public): Public members of the base class remain public in the derived class. Protected members remain protected, and private members are not accessible.

  • Protected Inheritance (protected): Public members of the base class become protected in the derived class, and protected members remain protected. Private members are still not accessible.

  • Private Inheritance (private): Both public and protected members of the base class become private in the derived class. Private members are not accessible.

Constructor and Destructor in Inheritance

  • Base Class Constructor: When a derived class object is created, the base class constructor is called before the derived class constructor.
  • Base Class Destructor: The base class destructor is called after the derived class destructor is executed (in case of dynamic memory allocation).
class Base {
public:
Base() { cout << “Base constructor called!” << endl; }
~Base() { cout << “Base destructor called!” << endl; }
};class Derived : public Base {
public:
Derived() { cout << “Derived constructor called!” << endl; }
~Derived() { cout << “Derived destructor called!” << endl; }
};

int main() {
Derived obj;
// Output:
// Base constructor called!
// Derived constructor called!
// Derived destructor called!
// Base destructor called!
return 0;
}

Method Overriding (Function Overriding)

When a derived class provides a new implementation for a function that is already defined in the base class, this is called function overriding. The function in the base class must be marked as virtual to allow overriding in derived classes.

class Base {
public:
virtual void display() { cout << “Base class display function” << endl; }
};class Derived : public Base {
public:
void display() override { cout << “Derived class display function” << endl; }
};

int main() {
Base* basePtr;
Derived derivedObj;
basePtr = &derivedObj;
basePtr->display(); // Calls the derived class function due to polymorphism
return 0;
}

Polymorphism allows objects to behave differently based on their actual type, even when referenced by a pointer or reference to a base class. Virtual functions enable polymorphic behavior, allowing function overriding to take place at runtime.

Benefits of Inheritance in C++

  • Code Reusability: Inheritance allows derived classes to reuse the code of the base class, reducing redundancy and preventing the need to rewrite common functionality.
  • Extensibility: New features can be added to an existing class without modifying its existing code, making it easier to extend and adapt to future requirements.
  • Modularity: Inheritance encourages modular design, where functionality is separated into distinct, manageable classes. This makes code easier to maintain and understand.
  • Maintaining Hierarchical Relationships: Inheritance helps in creating a clear hierarchy between classes (e.g., “Dog” is a type of “Animal”), which makes it easier to model real-world relationships.
  • Polymorphism Support: Inheritance enables polymorphism, allowing derived classes to provide specific implementations for base class methods, leading to flexible and dynamic behavior at runtime.

These benefits make inheritance a powerful feature in object-oriented programming (OOP) that aids in creating clean, efficient, and maintainable code.