Inheritance: Reusability and Hierarchy
Table of Contents
- What is Inheritance? (The
is-aRelationship) - Access Modes (
classvsstructdefaults) - Constructor Execution Order (Base ALWAYS first)
- Constructor Delegation (Passing data to Parent)
- Multiple Inheritance Syntax
- Deep Dive: Memory and Constructors
- Protected Access Modifier in depth
1. What is Inheritance?
When a child class inherits from a parent class, this is called inheritance.
We use inheritance when we have an is-a relationship.
Think of it like creating something specialized from something generalized.
- A
Monkeyis aAnimal. - A
Caris aVehicle. - A
Manageris anEmployee.
Why Inheritance?
- Reusability: You write common logic (like
eat()orsleep()) once in the Base class, and 50 different animal subclasses get it for free. - Code Modification: Changing a core behavior in the parent class automatically cascades down to all children.
- Data Hiding: You can keep parent data safe while still letting children use parent methods.
2. Access Modes (Public, Private, Protected Inheritance)
When you inherit, you must specify an access mode. This mode dictates how the outside world views the inherited members.
class Child : public Parent {};The Default Modes (Interview Gotcha):
- If you inherit using the
classkeyword (e.g.,class Child : Base), the default inheritance mode isprivate. - If you inherit using the
structkeyword (e.g.,struct Child : Base), the default inheritance mode ispublic.
How Modes Affect Inherited Members:
- Public Inheritance (
public Parent): Public members stay public. Protected members stay protected. Private members are inherited but inaccessible. This is the standard "is-a" relationship. - Protected Inheritance (
protected Parent): Public and protected members become protected in the child. - Private Inheritance (
private Parent): Public and protected members become private in the child. (Used for "implemented-in-terms-of", similar to composition).
3. Constructor Execution Order
When you create a child object, the compiler must build the parent parts of that object first.
Rule: In inheritance, Base class constructors are ALWAYS executed before the Derived class constructors. Destructors: Execute in the exact opposite order (Derived first, then Base).
class Animal {
public:
Animal() { cout << "Animal Born\n"; }
~Animal() { cout << "Animal Died\n"; }
};
class Monkey : public Animal {
public:
Monkey() { cout << "Monkey Born\n"; }
~Monkey() { cout << "Monkey Died\n"; }
};
int main() {
Monkey m;
// Output:
// Animal Born
// Monkey Born
// Monkey Died
// Animal Died
}4. Constructor Delegation (Passing data to Parent)
If the parent class does not have a default (empty) constructor, the child class must explicitly call the parent's parameterized constructor and pass the necessary data up the chain. We do this using the Member Initializer List.
The Complete Vehicle and Car Example
#include <iostream>
#include <string>
using namespace std;
// Base Class (Parent)
class Vehicle {
protected: // Protected so children can read them, but main() cannot
string name;
string model;
int noOfTyres;
public:
// Parent Parameterized Constructor
Vehicle(string _name, string _model, int _noOfTyres) {
this->name = _name;
this->model = _model;
this->noOfTyres = _noOfTyres;
cout << "1. Base Class (Vehicle) Constructor Called!" << endl;
}
};
// Derived Class (Child)
class Car : public Vehicle {
private:
int noOfDoors;
string transmissionType;
public:
// Child Constructor delegating values up to the Parent
Car(string _name, string _model, int _noOfTyres, int _noOfDoors, string _transmissionType)
: Vehicle(_name, _model, _noOfTyres) // <-- Passing data up to Parent!
{
// Now initializing Child-specific fields
this->noOfDoors = _noOfDoors;
this->transmissionType = _transmissionType;
cout << "2. Derived Class (Car) Constructor Called!" << endl;
}
void displayDetails() {
// Accessible because attributes are 'protected' in Vehicle
cout << "\n--- Car Details ---" << endl;
cout << "Name: " << name << ", Model: " << model << endl;
cout << "Tyres: " << noOfTyres << ", Doors: " << noOfDoors << endl;
cout << "Transmission: " << transmissionType << endl;
}
};
int main() {
// Creating a Car object
Car myCar("Civic", "2026-V", 4, 4, "Automatic");
myCar.displayDetails();
return 0;
}5. Multiple Inheritance
C++ is one of the few languages that allows Multiple Inheritance (a class can have more than one direct parent). Java and C# forbid this due to complexity.
Syntax for Multiple Inheritance
class ParentClassA {};
class ParentClassB {};
// Inheriting from both A and B
class ChildClass : public ParentClassA, private ParentClassB {
// Child class body
};Constructor Order in Multiple Inheritance:
Constructors are called in the exact order they are listed in the inheritance declaration, from left to right.
In ChildClass : public A, private B, A's constructor fires first, then B's, then ChildClass's.
The Diamond Problem (Briefly)
If A and B both inherit from a base class Grandparent, and Child inherits from both A and B, Child gets two copies of Grandparent. This creates severe memory bloat and ambiguous method calls.
Fix: Use virtual inheritance (class A : virtual public Grandparent), which tells the compiler to only create a single shared instance of the grandparent.