Skip to main content

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.

L1

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.
TermMeaningExample
Base / parentExisting class being reusedAnimal, Vehicle
Derived / childNew class that inheritsDog, Car
is-aDerived is a kind of BaseDog is an Animal
ReuseShare common memberseat() 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).

C++ inheritance infographic: is-a relationship, types single multiple multilevel hierarchical hybrid with diagrams, mode of inheritance, access table, Vehicle real-life analogy, benefits and use cases.
C++ inheritance — reuse, extend, and evolve class hierarchies
  • 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.
BenefitWhat you gain
ReusabilityShare base features across children
Less duplicationCommon code lives in one place
MaintenanceUpdate base → all derived benefit
ExtensibilityAdd new derived classes cleanly
RelationshipsClear is-a hierarchy
Polymorphism readyBase pointers to derived objects

Types of inheritance

  • C++ supports several inheritance shapes — pick the one that matches your design.
TypeDescriptionShape
SingleOne derived from one baseA → B
MultipleOne derived from many basesA, B → C
MultilevelChain of inheritanceA → B → C
HierarchicalMany derived from one baseA → B, A → C
HybridCombination of typesOften 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 **public inheritance**.
  • Private members of the base are **never** directly accessible in derived (regardless of mode).
Base memberpublic inheritanceprotected inheritanceprivate inheritance
publicpublic in derivedprotected in derivedprivate in derived
protectedprotectedprotectedprivate
privatenot accessiblenot accessiblenot 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.
L2

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

  • protected is 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).
L3

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.

L4

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;
}
L5

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.
L6

Practice Programs List

  1. Implement Animal → Dog / Cat (hierarchical) with a shared eat() and unique sounds.
  2. Build Person → Employee → Manager (multilevel) with show() at each level.
  3. Create Printer + Scanner → Copier (multiple) and call both behaviours.
  4. Print constructor/destructor messages to verify call order.
  5. Use a protected name in base; access it from derived show().
  6. Demonstrate that derived cannot access a private base field directly.
  7. Cause and fix an ambiguity with two bases that both have show().
  8. Model Vehicle → Car/Bike/Truck; add one unique method each.
  9. Write a tiny diamond with and without virtual bases; discuss sizeof/ambiguity.
  10. Compare public vs private inheritance on a small Base/Derived pair.
  11. List five real is-a hierarchies from apps you use.
  12. Refactor duplicated start()/stop() from Car and Bike into Vehicle.
  13. Add a derived constructor that passes values to the base constructor.
  14. Explain in comments when you would choose composition instead of inheritance.