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.8Access 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: Mary3. 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 method4. 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: 165. 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 calledCalling 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 CamryVirtual 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.2655Abstract 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
- Use virtual destructors in base classes with virtual functions
- Favor composition over inheritance when appropriate
- Keep inheritance hierarchies shallow
- Use protected for members that derived classes need
- Override virtual functions with the
overridekeyword - 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
-
Vehicle Hierarchy: Create base Vehicle class and derive Car, Bike, Truck
-
Employee System: Implement Employee base class with Manager, Developer, Intern
-
Banking System: Create Account base class with SavingsAccount, CheckingAccount
-
Game Characters: Design Character base class with Warrior, Mage, Archer
-
Media Library: Create Media base class with Book, Movie, Music
Inheritance is a powerful tool for creating well-organized, reusable code!