3.1 Inheritance — Types & Derivation Modes
What is Inheritance?
Inheritance is the mechanism by which a new class (derived class) acquires the properties and behaviours of an existing class (base class). It enables code reuse, extensibility, and modelling of "is-a" relationships.
class Vehicle { // base class
public:
int wheels;
void start() { cout << "Engine starts\n"; }
};
class Car : public Vehicle { // derived from Vehicle
public:
int seats;
void honk() { cout << "Beep!\n"; }
};
Car c;
c.start(); // inherited from Vehicle
c.wheels = 4; // inherited
c.honk(); // own
Terminology
| Term | Meaning |
|---|---|
| Base / Super / Parent class | The class being inherited from |
| Derived / Sub / Child class | The class doing the inheriting |
is-a relationship | Car is a Vehicle |
| Single inheritance | One base, one derived |
| Multiple inheritance | One derived from multiple bases |
| Multilevel inheritance | Chain: A → B → C |
| Hierarchical inheritance | One base, many derived |
| Hybrid inheritance | Mix of above |
Syntax
class Derived : access-specifier Base {
// ...
};
The access-specifier is public, protected, or private — covered shortly.
---
Why Inheritance?
| Benefit | Explanation |
|---|---|
| Code reuse | Don't rewrite features in every related class |
| Real-world modelling | "is-a" hierarchies match domains naturally |
| Extensibility | Add new specialised types without modifying existing code |
| Polymorphism foundation | Virtual functions need inheritance to work |
| Maintainability | Fix bug in base → all derived benefit |
---
Types of Inheritance
1. Single Inheritance
One base class → one derived class.
Base
│
▼
Derived
class A {
public:
void f1() { cout << "A::f1\n"; }
};
class B : public A { // single inheritance
public:
void f2() { cout << "B::f2\n"; }
};
B b;
b.f1(); // from A
b.f2(); // from B
---
2. Multiple Inheritance
A derived class inherits from two or more base classes.
Base1 Base2
\ /
\ /
Derived
class Worker {
public:
void work() { cout << "Working\n"; }
};
class Student {
public:
void study() { cout << "Studying\n"; }
};
class WorkingStudent : public Worker, public Student { // multiple
public:
void describe() { cout << "I work and study\n"; }
};
WorkingStudent ws;
ws.work(); // from Worker
ws.study(); // from Student
ws.describe(); // own
Multiple inheritance is powerful but risky — can cause the diamond problem (next lesson).
---
3. Multilevel Inheritance
A chain of inheritance: A → B → C (B derives from A, C derives from B).
A
│
▼
B
│
▼
C
class Grandfather {
public:
void g_method() { cout << "Grandfather\n"; }
};
class Father : public Grandfather {
public:
void f_method() { cout << "Father\n"; }
};
class Son : public Father {
public:
void s_method() { cout << "Son\n"; }
};
Son s;
s.g_method(); // from Grandfather (2 levels up)
s.f_method(); // from Father
s.s_method(); // own
---
4. Hierarchical Inheritance
One base class → multiple derived classes.
Base
/ | \
/ | \
▼ ▼ ▼
D1 D2 D3
class Shape {
public:
void draw() { cout << "Drawing shape\n"; }
};
class Circle : public Shape { /* ... */ };
class Square : public Shape { /* ... */ };
class Triangle : public Shape { /* ... */ };
Common in real-world OOP — one general type, many specialised subtypes.
---
5. Hybrid Inheritance
A combination of two or more of the above — usually involves multiple + multilevel or multiple + hierarchical.
Base
/ \
▼ ▼
D1 D2
\ /
▼ ▼
D3
This is the classic diamond problem layout — D3 inherits from D1 and D2, both of which inherit from Base. D3 ends up with two copies of Base — ambiguity. Solved with virtual base class (next lesson).
class A {
public:
int x;
};
class B : public A { /* ... */ };
class C : public A { /* ... */ };
class D : public B, public C { // diamond — D has two A's
public:
void test() {
// x = 5; // AMBIGUOUS — which A's x?
B::x = 5; // explicit qualification
C::x = 10;
}
};
---
Comparison of Inheritance Types — quick table
| Type | Diagram | Description |
|---|---|---|
| Single | A → B | One base, one derived |
| Multiple | A,B → C | Derived from two+ bases |
| Multilevel | A → B → C | Chain |
| Hierarchical | A → B, A → C | One base, many derived |
| Hybrid | mix | Combination |
---
Derivation Modes — public, protected, private
The access specifier in class Derived : MODE Base determines how base members are inherited:
Visibility transformation
| Base member | public derivation | protected derivation | private derivation |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | not inherited | not inherited | not inherited |
Private base members are never accessible in the derived class, regardless of derivation mode.
Examples
class Base {
public: int pub;
protected: int prot;
private: int priv;
};
class PubDerived : public Base {
void f() {
pub = 1; // OK — public stays public
prot = 2; // OK — protected stays protected
// priv = 3; // ERROR — private never inherited
}
};
class ProtDerived : protected Base {
void f() {
pub = 1; // OK — public becomes protected
prot = 2; // OK
// priv = 3; // ERROR
}
};
class PrivDerived : private Base {
void f() {
pub = 1; // OK — public becomes private (still accessible inside class)
prot = 2; // OK
// priv = 3; // ERROR
}
};
int main() {
PubDerived d1;
d1.pub = 5; // OK — still public outside
ProtDerived d2;
// d2.pub = 5; // ERROR — pub became protected, not accessible from main
PrivDerived d3;
// d3.pub = 5; // ERROR — pub became private
return 0;
}
What each derivation mode means semantically
| Mode | Semantic |
|---|---|
public | "is-a" — Car is a Vehicle; external code can use derived as base |
protected | "implemented in terms of, internally" — used in further inheritance |
private | "implemented in terms of, hidden" — composition via inheritance; external code doesn't know |
In practice: ~99% of inheritance ispublic.protectedandprivatederivation are rare in real code.
Default derivation mode
- For
class:private(soclass D : Base=class D : private Base) - For
struct:public
Always be explicit — write public, protected, or private — to avoid confusion.
---
Aggregation vs Composition vs Classification
Classification (Inheritance) — "is-a"
class Car : public Vehicle {}; // Car IS A Vehicle
Composition — "has-a" (strong ownership)
class Engine {};
class Car {
Engine engine; // Car HAS A Engine — by value (lifetime tied to Car)
};
Aggregation — "has-a" (weak ownership)
class Department {};
class University {
vector<Department*> depts; // University HAS Departments (independent lifetime)
};
When to choose what
| Relationship | Use |
|---|---|
| is-a (Car is a Vehicle) | Inheritance |
| has-a, strong (Car has an Engine — engine destroyed with car) | Composition |
| has-a, weak (University has Departments — but they can exist separately) | Aggregation |
Modern advice: Prefer composition over inheritance. Inheritance creates tight coupling between base and derived. Composition is more flexible and avoids many OOP design pitfalls.
---
Composition vs Classification — exam comparison
| Aspect | Classification (Inheritance) | Composition |
|---|---|---|
| Relationship | "is-a" | "has-a" |
| Coupling | Tight | Loose |
| Flexibility | Less (compile-time) | More (runtime) |
| Reuse via | Inheriting | Including as member |
| Replaceability | Hard | Easy |
| Polymorphism | Yes | Yes (via interface composition) |
---
Example — Library Management
class Item {
protected:
int id;
string title;
public:
Item(int i, string t) : id(i), title(t) {}
void display() {
cout << id << ": " << title << endl;
}
};
class Book : public Item { // Book IS A Item
private:
string author;
public:
Book(int i, string t, string a) : Item(i, t), author(a) {}
void showAuthor() {
cout << "Author: " << author << endl;
}
};
class Magazine : public Item { // Magazine IS A Item
private:
int issue;
public:
Magazine(int i, string t, int is) : Item(i, t), issue(is) {}
void showIssue() {
cout << "Issue: " << issue << endl;
}
};
int main() {
Book b(1, "C++ Primer", "Stanley Lippman");
Magazine m(2, "Time", 47);
b.display(); // inherited
b.showAuthor();
m.display();
m.showIssue();
return 0;
}
---
Study deep
- Inheritance creates one of the strongest coupling forces in OOP. A derived class depends on the base class's interface AND implementation. Changes to the base ripple to all derived. Use sparingly.
is-atest for choosing inheritance. If "Car is a Vehicle" is naturally true, inherit. If you're saying "Car has-a Vehicle" or "Car uses Vehicle," prefer composition.
- Multiple inheritance is controversial. Java forbids it (allows multiple interface inheritance only). C++ allows full multiple inheritance — flexible but enables the diamond problem. Use mixins / interfaces approach for clarity.
- The "fragile base class" problem. If many classes inherit from a base, changing the base risks breaking all of them. This is one reason modern systems prefer composition.
- Java's "implements" = C++'s pure virtual classes. Java distinguishes "extends" (class inheritance, single) from "implements" (interface inheritance, multiple). C++ doesn't have keywords for this — but a class with only pure virtual methods is effectively an interface.
Key Terms — Lesson 3.1
The terms below define inheritance vocabulary — the third OOP pillar and a guaranteed Unit-III topic.
Inheritance — The OOP mechanism by which a new class (derived / subclass / child) acquires the properties and behaviours of an existing class (base / superclass / parent), with the option to add new members or override inherited ones. Inheritance models the "is-a" relationship and enables code reuse, extensibility, and polymorphism.
Base Class / Parent Class / Superclass — The class being inherited from. Its members are exposed (subject to access specifiers) to the derived class. The base provides the common behaviour that derived classes specialise.
Derived Class / Child Class / Subclass — A class that inherits from another. The derived class can use the base's accessible members, add its own, and override the base's virtual functions.
Single Inheritance — A derived class has one direct base class. The simplest form: class Car : public Vehicle. Easy to understand, no ambiguity issues, the default style in most Java code (where multiple inheritance is forbidden).
Multiple Inheritance — A derived class has two or more direct base classes: class Plane : public Vehicle, public Aircraft. C++ supports it; Java and C# do not (they allow multiple interface inheritance only). Multiple inheritance enables genuine multi-role classes but introduces ambiguity issues (the diamond problem).
Multilevel Inheritance — A chain of inheritance: Vehicle → Car → SportsCar. SportsCar inherits from Car, which inherits from Vehicle. Each level adds specialisation.
Hierarchical Inheritance — One base class has multiple direct derived classes — Vehicle is inherited by Car, Bike, Truck. The base captures common behaviour; each derived class specialises.
Hybrid Inheritance — A combination of two or more inheritance styles in a single hierarchy — e.g., multiple + multilevel. Hybrid hierarchies often suffer the diamond problem.
Derivation Mode / Access Specifier (in Inheritance) — A specifier (public, protected, or private) used after the colon in the derived class declaration: class Car : public Vehicle. Controls how inherited members appear in the derived class.
Public Derivation — class Derived : public Base. Public members of Base remain public in Derived; protected members remain protected; private members are not accessible. The most common derivation mode; models true "is-a."
Protected Derivation — class Derived : protected Base. Public members of Base become protected in Derived; protected stay protected; private inaccessible. Used rarely — the derived class wants to use the base internally but not expose it.
Private Derivation — class Derived : private Base. Public and protected members of Base become private in Derived. The derived class uses the base implementation but does not expose any inheritance relationship — equivalent to composition in effect. The default if no access specifier is given.
Visibility Inheritance Matrix — The 3×3 table showing how each base-class access level (public/protected/private) maps to derived-class visibility under each derivation mode. Public-derived preserves access; protected-derived caps at protected; private-derived caps at private.
"is-a" Relationship — The semantic test for inheritance. A SportsCar is a Car; Car is a Vehicle; Manager is an Employee. If the relationship is naturally "is-a," inheritance fits. If not, composition is usually the right choice.
"has-a" Relationship — The semantic test for composition. A Car has an Engine; a University has Departments; an Order has Line Items. "has-a" relationships are modelled by including instances of the other class as data members, not by inheriting.
Composition vs Inheritance — Two reuse mechanisms. Inheritance (is-a) makes the derived class a kind of the base; the derived shares the base's interface and implementation. Composition (has-a) embeds another object as a member; the containing class delegates to it but does not inherit its interface. Modern advice: "prefer composition over inheritance" because composition is more flexible.
Aggregation — A form of composition where the contained objects can exist independently of the container. A University aggregates Departments (the Departments could exist without the University). Contrast with strict composition, where contained objects share the container's lifetime (Book composes Chapters).
Override — When a derived class defines a method with the same signature as a base-class method, replacing the base's version. Override is required for runtime polymorphism (combined with virtual). C++11 added the override keyword to make intent explicit and let the compiler catch mismatches.
Hide — When a derived class declares a member (variable or function) with the same name as one in the base class. The derived name hides the base name; accessing the base version requires explicit scope resolution (Base::method()). Hiding is rarely intentional and usually a bug.
Constructor Chaining (in Inheritance) — When a derived object is constructed, the base-class constructor runs first, then the derived constructor. The derived can specify which base constructor via the initialiser list: Derived(int x) : Base(x) {}. Without specification, the base's default constructor is called.
Destructor Chaining (in Inheritance) — When a derived object is destroyed, the derived destructor runs first, then the base destructor. Order is the reverse of construction. For polymorphic base classes, declare the base destructor virtual so derived destructors run correctly through base pointers.
Reusability (in Inheritance) — The economic benefit of inheritance: writing once in the base class, reusing automatically in all derived classes. Reusability is what justifies the cost of inheritance's tight coupling.
Extensibility — The ability to add new derived classes without modifying existing code. New Shape subclasses can be added without touching the rest of the system, as long as they conform to the base Shape interface. The Open-Closed Principle in SOLID.
Fragile Base Class Problem — A maintenance hazard: changing a base class can silently break many derived classes because they depend on the base's behaviour. The more classes inherit from a base, the riskier any change becomes. One of the strongest arguments for shallow hierarchies and composition.
Liskov Substitution Principle (LSP) — Robert Martin's principle (Barbara Liskov, 1987): subtypes must be substitutable for their base types. If Square extends Rectangle but breaks code that relies on Rectangle's behaviour (set-width-independently-of-height), the design violates LSP. Often signals "this should not be inheritance."
Empty Base Optimisation (EBO) — A C++ compiler optimisation: a derived class that inherits from an empty base class (no data members) does not pay the cost of an additional byte for the base subobject. Used heavily by the STL.
---
PYQ pattern (very common): "Explain types of inheritance in C++ with diagrams." — Define inheritance; show 5 types (single, multiple, multilevel, hierarchical, hybrid) with diagrams + 1-line examples each.
PYQ pattern: "Differentiate public, protected and private derivation." — Tabulate the 3×3 visibility transformation; explain semantic of each; mention public is the common case.
PYQ pattern: "What is aggregation? Differentiate it from inheritance / composition." — Define has-a vs is-a; table the differences; show code examples (University with Departments).