C++ OOP
Inheritance
Complete lesson for Inheritance using LEARNCODEGURU’s 6-level learning model — from basics to advanced practice, with C++ OOP and STL where relevant.
Basics — Inheritance
Section: C++ OOP. C++ inheritance — is-a relationships, types of inheritance, access modes, and real-life examples.
What is inheritance?
- **Inheritance** lets a **derived class** acquire properties and behaviours of an existing **base class**.
- It models an **“is-a”** relationship: Dog **is an** Animal; Car **is a** Vehicle.
- Promotes **reuse** — write common code once in the base, extend it in derived classes.
- Syntax:
class Derived : public Base { ... }; - **Real-life:** Vehicle → Car / Bike / Truck share start/stop/fuel, each adds its own features.
| Term | Meaning | Example |
|---|---|---|
| Base / parent | Existing class being reused | Animal, Vehicle |
| Derived / child | New class that inherits | Dog, Car |
| is-a | Derived is a kind of Base | Dog is an Animal |
| Reuse | Share common members | eat() in Animal used by Dog |
Inheritance — reuse, extend, is-a hierarchies
Inheritance lets a derived class acquire features of a base class. The diagram covers all inheritance types, access modes, Vehicle analogies, and key rules (private not accessible, ctors not inherited).
- is-a: Dog is an Animal; Car is a Vehicle.
- Types: single, multiple, multilevel, hierarchical, hybrid.
- Modes: public (common), protected, private inheritance.
- Remember: private base members stay inaccessible; ctors/dtors are not inherited.
Why use inheritance?
- Code reusability and less duplication.
- Easier maintenance — fix once in the base.
- Extensibility — add new derived types without rewriting shared logic.
- Natural modeling of related types; supports polymorphism later.
| Benefit | What you gain |
|---|---|
| Reusability | Share base features across children |
| Less duplication | Common code lives in one place |
| Maintenance | Update base → all derived benefit |
| Extensibility | Add new derived classes cleanly |
| Relationships | Clear is-a hierarchy |
| Polymorphism ready | Base pointers to derived objects |
Types of inheritance
- C++ supports several inheritance shapes — pick the one that matches your design.
| Type | Description | Shape |
|---|---|---|
| Single | One derived from one base | A → B |
| Multiple | One derived from many bases | A, B → C |
| Multilevel | Chain of inheritance | A → B → C |
| Hierarchical | Many derived from one base | A → B, A → C |
| Hybrid | Combination of types | Often forms a diamond |
Single inheritance
- One base, one derived — the most common form.
- **Real-life:** Animal → Dog.
#include <iostream>
using namespace std;
class Animal {
public:
void eat() { cout << "Eating\n"; }
};
class Dog : public Animal {
public:
void bark() { cout << "Barking\n"; }
};
int main() {
Dog d;
d.eat(); // inherited
d.bark(); // own
return 0;
} Multilevel inheritance
- Derived class becomes base for another derived class: A → B → C.
- **Real-life:** LivingBeing → Animal → Dog.
class A {
public:
void fa() { /* ... */ }
};
class B : public A {
public:
void fb() { /* ... */ }
};
class C : public B {
public:
void fc() { /* ... */ }
};
// C has fa, fb, fc Hierarchical inheritance
- One base, many derived classes.
- **Real-life:** Vehicle → Car, Bike, Truck.
class Vehicle {
public:
void start() { /* ... */ }
};
class Car : public Vehicle {};
class Bike : public Vehicle {};
class Truck : public Vehicle {}; Multiple inheritance
- One class inherits from two or more bases:
class C : public A, public B. - Powerful but can cause **ambiguity** if both bases have the same member name.
- **Real-life:** TeachingAssistant is a Teacher and a Student (carefully designed).
#include <iostream>
using namespace std;
class Printer {
public:
void print() { cout << "Print\n"; }
};
class Scanner {
public:
void scan() { cout << "Scan\n"; }
};
class Copier : public Printer, public Scanner {};
int main() {
Copier c;
c.print();
c.scan();
return 0;
} Hybrid inheritance & diamond problem (intro)
- Hybrid mixes inheritance types — often creates a **diamond**: D inherits B and C, both inherit A.
- Without care, D may get **two copies** of A → ambiguity.
- Fix with **virtual inheritance** (covered more in Virtual Functions / advanced notes).
class A { public: int x = 1; };
class B : virtual public A {};
class C : virtual public A {};
class D : public B, public C {};
// D has one shared A subobject when using virtual Modes of inheritance (public / protected / private)
- The inheritance access specifier changes how base members appear in the derived class.
- Most OOP “is-a” designs use **
publicinheritance**. - Private members of the base are **never** directly accessible in derived (regardless of mode).
| Base member | public inheritance | protected inheritance | private inheritance |
|---|---|---|---|
| public | public in derived | protected in derived | private in derived |
| protected | protected | protected | private |
| private | not accessible | not accessible | not accessible |
class Base {
public:
int pub = 1;
protected:
int prot = 2;
private:
int priv = 3;
};
class Pub : public Base {}; // pub stays public
class Prot : protected Base {}; // pub becomes protected
class Priv : private Base {}; // pub becomes private Key points to remember
- Inheritance is transitive along a chain (C gets A via B).
- Constructors and destructors are **not inherited** — but they are called in order.
- Use derived objects to access inherited public members.
- Prefer public inheritance for true is-a relationships.
Advanced — Inheritance
Constructor / destructor order
- Construction: **base first**, then derived.
- Destruction: **derived first**, then base (reverse).
- Derived constructors should initialize bases via initializer lists:
Derived(...) : Base(...) {}.
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Base ctor\n"; }
~Base() { cout << "Base dtor\n"; }
};
class Derived : public Base {
public:
Derived() { cout << "Derived ctor\n"; }
~Derived() { cout << "Derived dtor\n"; }
};
int main() {
Derived d;
return 0;
}
/* Base ctor
Derived ctor
Derived dtor
Base dtor */ Function overriding (preview of polymorphism)
- Derived can redefine a base function with the same signature.
- For runtime polymorphism via base pointers, mark the base function
virtual(next lessons). - Without virtual, calling through a base pointer uses the base version (static binding).
class Shape {
public:
virtual void draw() const { /* base */ }
virtual ~Shape() = default;
};
class Circle : public Shape {
public:
void draw() const override { /* circle */ }
}; Ambiguity in multiple inheritance
- If two bases define
f(),obj.f()is ambiguous — qualify:obj.A::f()/obj.B::f()or redesign. - Diamond without virtual bases duplicates the top base subobject.
Protected members in inheritance
protectedis for “derived may use, outside world may not”.- Useful for shared hooks; do not overexpose internals as protected.
Real-life inheritance models
- GUI: Widget → Button / TextBox / Label.
- Games: Entity → Player / Enemy / NPC.
- Employees: Employee → Manager / Developer / Intern.
- Devices: Device → Printer / Scanner → AllInOne (multiple/hybrid carefully).
Tricky Interview Points
Q1) What is inheritance in C++?
Answer An OOP feature where a derived class acquires members of a base class, modeling an is-a relationship and enabling reuse.
Q2) What are the types of inheritance?
Answer Single, multiple, multilevel, hierarchical, and hybrid.
Q3) What is public inheritance?
Answer The common is-a form: public base members stay public in derived, protected stay protected; private base members remain inaccessible.
Q4) Are private members of the base inherited?
Answer They are part of the object layout but not directly accessible in the derived class. Derived uses public/protected base interfaces or friends.
Q5) Are constructors inherited?
Answer Constructors/destructors are not inherited as ordinary members. Base constructors run first when a derived object is created.
Q6) What is the diamond problem?
Answer In hybrid/multiple inheritance, two paths to the same base can duplicate that base and cause ambiguity. Mitigate with virtual base classes.
Q7) Difference between multilevel and multiple inheritance?
Answer Multilevel is a chain A→B→C. Multiple means one class has two or more direct bases.
Q8) What is hierarchical inheritance?
Answer One base class with several derived classes (Vehicle → Car, Bike, Truck).
Q9) Constructor call order in inheritance?
Answer Base constructor first, then derived. Destructors run in reverse order.
Q10) Why prefer public inheritance for is-a?
Answer It preserves the public interface of the base so derived objects can be used where the base is expected (especially with polymorphism).
Q11) What does protected inheritance do?
Answer Public and protected base members become protected in the derived class — useful for implementation reuse, less common for is-a APIs.
Q12) Give a real-life example of inheritance.
Answer Vehicle as base with start/stop; Car, Bike, Truck as derived classes adding their own behaviours.
Simple Programs
Single inheritance — Animal / Dog
#include <iostream>
using namespace std;
class Animal {
public:
void eat() { cout << "Eating\n"; }
};
class Dog : public Animal {
public:
void bark() { cout << "Barking\n"; }
};
int main() {
Dog d;
d.eat();
d.bark();
return 0;
} Multilevel — A / B / C
#include <iostream>
using namespace std;
class A {
public:
void fa() { cout << "A\n"; }
};
class B : public A {
public:
void fb() { cout << "B\n"; }
};
class C : public B {
public:
void fc() { cout << "C\n"; }
};
int main() {
C obj;
obj.fa(); obj.fb(); obj.fc();
return 0;
} Hierarchical — Vehicle family
#include <iostream>
using namespace std;
class Vehicle {
public:
void start() { cout << "Vehicle start\n"; }
};
class Car : public Vehicle {
public:
void drive() { cout << "Car drive\n"; }
};
class Bike : public Vehicle {
public:
void ride() { cout << "Bike ride\n"; }
};
int main() {
Car c; Bike b;
c.start(); c.drive();
b.start(); b.ride();
return 0;
} Multiple inheritance — Copier
#include <iostream>
using namespace std;
class Printer {
public:
void printDoc() { cout << "Printing\n"; }
};
class Scanner {
public:
void scanDoc() { cout << "Scanning\n"; }
};
class Copier : public Printer, public Scanner {};
int main() {
Copier m;
m.printDoc();
m.scanDoc();
return 0;
} Ctor / dtor order
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Base\n"; }
~Base() { cout << "~Base\n"; }
};
class Derived : public Base {
public:
Derived() { cout << "Derived\n"; }
~Derived() { cout << "~Derived\n"; }
};
int main() {
Derived d;
return 0;
} Protected member used by derived
#include <iostream>
#include <string>
using namespace std;
class Person {
protected:
string name;
public:
Person(string n) : name(n) {}
};
class Student : public Person {
int roll;
public:
Student(string n, int r) : Person(n), roll(r) {}
void show() const { cout << name << " " << roll << "\n"; }
};
int main() {
Student s("Asha", 10);
s.show();
return 0;
} Ambiguity resolution (qualify)
#include <iostream>
using namespace std;
class A {
public:
void show() { cout << "A\n"; }
};
class B {
public:
void show() { cout << "B\n"; }
};
class C : public A, public B {};
int main() {
C obj;
obj.A::show();
obj.B::show();
return 0;
} Problem Solving Tricks
- Think is-a: Dog is an Animal — then public inheritance fits.
- Private base members are not directly usable in derived.
- Most designs use public inheritance.
- Ctor: base first; dtor: derived first.
- Initialize bases in the derived initializer list.
- Multiple inheritance: watch name clashes — qualify or redesign.
- Diamond? Consider virtual inheritance.
- Do not inherit just to reuse code if has-a (composition) is clearer.
- Keep hierarchies shallow when possible.
- protected = for derived collaborators, not for the world.
- Constructors/destructors are not “inherited” as callable members.
- Draw the inheritance diagram before coding hybrid designs.
Practice Programs List
- Implement Animal → Dog / Cat (hierarchical) with a shared eat() and unique sounds.
- Build Person → Employee → Manager (multilevel) with show() at each level.
- Create Printer + Scanner → Copier (multiple) and call both behaviours.
- Print constructor/destructor messages to verify call order.
- Use a protected name in base; access it from derived show().
- Demonstrate that derived cannot access a private base field directly.
- Cause and fix an ambiguity with two bases that both have show().
- Model Vehicle → Car/Bike/Truck; add one unique method each.
- Write a tiny diamond with and without virtual bases; discuss sizeof/ambiguity.
- Compare public vs private inheritance on a small Base/Derived pair.
- List five real is-a hierarchies from apps you use.
- Refactor duplicated start()/stop() from Car and Bike into Vehicle.
- Add a derived constructor that passes values to the base constructor.
- Explain in comments when you would choose composition instead of inheritance.