Skip to Content
ClassesInheritance

Inheritance in C++

Inheritance is a fundamental OOP concept that allows a class to inherit properties and methods from another class. It enables code reusability and establishes a relationship between classes.

What is Inheritance?

Inheritance allows you to create a new class (derived/child class) from an existing class (base/parent class). The derived class inherits all members of the base class.

Benefits:

  • Code reusability
  • Extensibility
  • Method overriding
  • Establishes “is-a” relationship

Basic Syntax

class BaseClass { // Base class members }; class DerivedClass : access_specifier BaseClass { // Derived class members };

Simple Inheritance Example

#include <iostream> #include <string> using namespace std; // Base class class Person { protected: string name; int age; public: Person(string n, int a) : name(n), age(a) {} void display() { cout << "Name: " << name << endl; cout << "Age: " << age << endl; } }; // Derived class class Student : public Person { private: int rollNumber; double gpa; public: Student(string n, int a, int roll, double g) : Person(n, a), rollNumber(roll), gpa(g) {} void displayStudent() { display(); // Call base class method cout << "Roll Number: " << rollNumber << endl; cout << "GPA: " << gpa << endl; } }; int main() { Student s1("Alice", 20, 101, 3.8); s1.displayStudent(); return 0; }

Output:

Name: Alice Age: 20 Roll Number: 101 GPA: 3.8

Access Specifiers in Inheritance

Public Inheritance

  • Public members of base class become public in derived class
  • Protected members remain protected
class Derived : public Base { // Public and protected members accessible };

Protected Inheritance

  • Public and protected members of base class become protected
class Derived : protected Base { // Public becomes protected };

Private Inheritance

  • All members of base class become private
class Derived : private Base { // All members become private };

Types of Inheritance

1. Single Inheritance

One class inherits from one base class:

#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 dog; dog.eat(); // Inherited method dog.bark(); // Own method return 0; }

Output:

Eating... Barking...

2. Multiple Inheritance

A class inherits from multiple base classes:

#include <iostream> using namespace std; class Father { protected: string fatherName; public: Father(string fn) : fatherName(fn) {} void displayFather() { cout << "Father: " << fatherName << endl; } }; class Mother { protected: string motherName; public: Mother(string mn) : motherName(mn) {} void displayMother() { cout << "Mother: " << motherName << endl; } }; class Child : public Father, public Mother { private: string childName; public: Child(string fn, string mn, string cn) : Father(fn), Mother(mn), childName(cn) {} void displayChild() { cout << "Child: " << childName << endl; displayFather(); displayMother(); } }; int main() { Child c("John", "Mary", "Tom"); c.displayChild(); return 0; }

Output:

Child: Tom Father: John Mother: Mary

3. Multilevel Inheritance

Chain of inheritance:

#include <iostream> using namespace std; class GrandParent { public: void grandParentMethod() { cout << "GrandParent method" << endl; } }; class Parent : public GrandParent { public: void parentMethod() { cout << "Parent method" << endl; } }; class Child : public Parent { public: void childMethod() { cout << "Child method" << endl; } }; int main() { Child c; c.grandParentMethod(); // From GrandParent c.parentMethod(); // From Parent c.childMethod(); // Own method return 0; }

Output:

GrandParent method Parent method Child method

4. Hierarchical Inheritance

Multiple classes inherit from one base class:

#include <iostream> using namespace std; class Shape { protected: double dimension; public: Shape(double d) : dimension(d) {} }; class Circle : public Shape { public: Circle(double r) : Shape(r) {} double getArea() { return 3.14159 * dimension * dimension; } }; class Square : public Shape { public: Square(double s) : Shape(s) {} double getArea() { return dimension * dimension; } }; int main() { Circle circle(5); Square square(4); cout << "Circle area: " << circle.getArea() << endl; cout << "Square area: " << square.getArea() << endl; return 0; }

Output:

Circle area: 78.5398 Square area: 16

5. Hybrid Inheritance

Combination of multiple types:

#include <iostream> using namespace std; class A { public: void methodA() { cout << "Method from A" << endl; } }; class B : public A { public: void methodB() { cout << "Method from B" << endl; } }; class C : public A { public: void methodC() { cout << "Method from C" << endl; } }; class D : public B, public C { public: void methodD() { cout << "Method from D" << endl; } }; int main() { D obj; obj.methodB(); obj.methodC(); obj.methodD(); // obj.methodA(); // Ambiguous! Which A? From B or C? return 0; }

Method Overriding

Derived class can override base class methods:

#include <iostream> using namespace std; class Animal { public: virtual void makeSound() { cout << "Animal makes a sound" << endl; } }; class Dog : public Animal { public: void makeSound() override { cout << "Dog barks: Woof! Woof!" << endl; } }; class Cat : public Animal { public: void makeSound() override { cout << "Cat meows: Meow! Meow!" << endl; } }; int main() { Animal* animal1 = new Dog(); Animal* animal2 = new Cat(); animal1->makeSound(); // Calls Dog's method animal2->makeSound(); // Calls Cat's method delete animal1; delete animal2; return 0; }

Output:

Dog barks: Woof! Woof! Cat meows: Meow! Meow!

Constructor and Destructor in Inheritance

Constructor Execution Order

Base class constructor is called first, then derived class:

#include <iostream> using namespace std; 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 d; return 0; }

Output:

Base constructor called Derived constructor called Derived destructor called Base destructor called

Calling Base Class Constructor

#include <iostream> using namespace std; class Vehicle { protected: string brand; int year; public: Vehicle(string b, int y) : brand(b), year(y) { cout << "Vehicle constructor" << endl; } }; class Car : public Vehicle { private: string model; public: Car(string b, int y, string m) : Vehicle(b, y), model(m) { cout << "Car constructor" << endl; } void display() { cout << year << " " << brand << " " << model << endl; } }; int main() { Car c("Toyota", 2023, "Camry"); c.display(); return 0; }

Output:

Vehicle constructor Car constructor 2023 Toyota Camry

Virtual Functions and Polymorphism

#include <iostream> using namespace std; class Shape { public: virtual double getArea() { return 0; } virtual void display() { cout << "This is a shape" << endl; } }; class Rectangle : public Shape { private: double length, width; public: Rectangle(double l, double w) : length(l), width(w) {} double getArea() override { return length * width; } void display() override { cout << "Rectangle: " << length << "x" << width << endl; } }; class Circle : public Shape { private: double radius; public: Circle(double r) : radius(r) {} double getArea() override { return 3.14159 * radius * radius; } void display() override { cout << "Circle with radius: " << radius << endl; } }; int main() { Shape* shapes[2]; shapes[0] = new Rectangle(5, 3); shapes[1] = new Circle(4); for (int i = 0; i < 2; i++) { shapes[i]->display(); cout << "Area: " << shapes[i]->getArea() << endl << endl; } delete shapes[0]; delete shapes[1]; return 0; }

Output:

Rectangle: 5x3 Area: 15 Circle with radius: 4 Area: 50.2655

Abstract Classes

A class with at least one pure virtual function:

#include <iostream> using namespace std; class Shape { // Abstract class public: virtual double getArea() = 0; // Pure virtual function virtual void display() = 0; }; class Triangle : public Shape { private: double base, height; public: Triangle(double b, double h) : base(b), height(h) {} double getArea() override { return 0.5 * base * height; } void display() override { cout << "Triangle with base " << base << " and height " << height << endl; } }; int main() { // Shape s; // Error: Cannot instantiate abstract class Triangle t(6, 8); t.display(); cout << "Area: " << t.getArea() << endl; return 0; }

Best Practices

  1. Use virtual destructors in base classes with virtual functions
  2. Favor composition over inheritance when appropriate
  3. Keep inheritance hierarchies shallow
  4. Use protected for members that derived classes need
  5. Override virtual functions with the override keyword
  6. Make interfaces abstract with pure virtual functions

Common Pitfalls

1. Diamond Problem

Occurs in multiple inheritance when two base classes have the same base class

2. Slicing

Occurs when derived class object is assigned to base class object

3. Forgetting Virtual Destructor

Can cause memory leaks

Practice Exercises

  1. Vehicle Hierarchy: Create base Vehicle class and derive Car, Bike, Truck

  2. Employee System: Implement Employee base class with Manager, Developer, Intern

  3. Banking System: Create Account base class with SavingsAccount, CheckingAccount

  4. Game Characters: Design Character base class with Warrior, Mage, Archer

  5. Media Library: Create Media base class with Book, Movie, Music

Inheritance is a powerful tool for creating well-organized, reusable code!

Last updated on