Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

C++ Inheritance Single, Multiple, Multilevel: Tutorial, Examples, FAQs & Interview Tips

What is Inheritance?

Inheritance allows a derived class (child) to acquire the properties and methods of a base class (parent). It promotes code reuse and establishes an "is-a" relationship.

Syntax: class Derived : accessSpecifier Base { ... };

Inheritance Typepublic members becomeprotected members become
publicpublic in derivedprotected in derived
protectedprotected in derivedprotected in derived
privateprivate in derivedprivate in derived
Single Inheritance
#include <iostream>
#include <string>
using namespace std;

// Base class
class Animal {
protected:
    string name;
    int age;

public:
    Animal(string name, int age) : name(name), age(age) {}

    void eat()   { cout << name << " is eating" << endl; }
    void sleep() { cout << name << " is sleeping" << endl; }

    void info() {
        cout << "Name: " << name << ", Age: " << age << endl;
    }
};

// Derived class - inherits from Animal
class Dog : public Animal {
private:
    string breed;

public:
    // Call base constructor via initializer list
    Dog(string name, int age, string breed)
        : Animal(name, age), breed(breed) {}

    void bark() { cout << name << " says: Woof!" << endl; }

    void info() {  // override base info()
        Animal::info();  // call base version
        cout << "Breed: " << breed << endl;
    }
};

int main() {
    Dog d("Rex", 3, "German Shepherd");
    d.eat();    // inherited from Animal
    d.sleep();  // inherited from Animal
    d.bark();   // Dog's own method
    d.info();   // Dog's overridden info()

    return 0;
}

Multilevel and Multiple Inheritance

Multilevel and Multiple Inheritance
#include <iostream>
using namespace std;

class Vehicle {
public:
    void start() { cout << "Vehicle started" << endl; }
};

class Car : public Vehicle {
public:
    void drive() { cout << "Car driving" << endl; }
};

// Multilevel: ElectricCar -> Car -> Vehicle
class ElectricCar : public Car {
public:
    void charge() { cout << "Charging battery" << endl; }
};

int main() {
    ElectricCar ec;
    ec.start();   // from Vehicle
    ec.drive();   // from Car
    ec.charge();  // own method
    return 0;
}
#include <iostream>
using namespace std;

class Flyable {
public:
    void fly() { cout << "Flying" << endl; }
};

class Swimmable {
public:
    void swim() { cout << "Swimming" << endl; }
};

// Multiple inheritance: Duck inherits from both
class Duck : public Flyable, public Swimmable {
public:
    void quack() { cout << "Quack!" << endl; }
};

int main() {
    Duck d;
    d.fly();    // from Flyable
    d.swim();   // from Swimmable
    d.quack();  // own method
    return 0;
}

Constructor and Destructor Call Order

In inheritance, constructors are called base first, derived last. Destructors are called in reverse order "” derived first, base last.

Constructor / Destructor Order
#include <iostream>
using namespace std;

class Base {
public:
    Base()  { cout << "Base constructor"  << endl; }
    ~Base() { cout << "Base destructor"   << endl; }
};

class Derived : public Base {
public:
    Derived()  { cout << "Derived constructor"  << endl; }
    ~Derived() { cout << "Derived destructor"   << endl; }
};

int main() {
    Derived d;
    return 0;
}

/*
Output:
Base constructor       <-- base first
Derived constructor
Derived destructor     <-- derived first on destruction
Base destructor
*/

Virtual Destructor "” Why It Matters

When you delete a derived object through a base class pointer, the base destructor is called "” not the derived one. This causes a memory leak if the derived class allocates resources. The fix: always declare the base class destructor as virtual.

Virtual Destructor "” Memory Leak vs Safe
#include <iostream>
using namespace std;

// WITHOUT virtual destructor "” memory leak!
class BadBase {
public:
    ~BadBase() { cout << "BadBase destructor" << endl; }
};
class BadDerived : public BadBase {
    int *data;
public:
    BadDerived() { data = new int[100]; }
    ~BadDerived() {
        delete[] data;  // NEVER called when deleted via BadBase*
        cout << "BadDerived destructor" << endl;
    }
};

// WITH virtual destructor "” correct!
class GoodBase {
public:
    virtual ~GoodBase() { cout << "GoodBase destructor" << endl; }
};
class GoodDerived : public GoodBase {
    int *data;
public:
    GoodDerived() { data = new int[100]; }
    ~GoodDerived() override {
        delete[] data;  // called correctly
        cout << "GoodDerived destructor" << endl;
    }
};

int main() {
    // Memory leak "” BadDerived destructor never called
    BadBase *b = new BadDerived();
    delete b;  // only BadBase::~BadBase() runs!

    cout << "---" << endl;

    // Correct "” both destructors called
    GoodBase *g = new GoodDerived();
    delete g;  // GoodDerived::~GoodDerived() then GoodBase::~GoodBase()

    return 0;
}
// Rule: if a class has ANY virtual function, give it a virtual destructor.

Diamond Problem and Virtual Inheritance

The diamond problem occurs in multiple inheritance when two base classes share a common ancestor, causing the grandparent's members to be duplicated. virtual inheritance solves this by ensuring only one copy of the grandparent exists.

Diamond Problem and Virtual Inheritance
#include <iostream>
using namespace std;

//        Animal
//       /      \
//    Dog       Cat
//       \      /
//        DogCat   <-- diamond!

// WITHOUT virtual inheritance "” ambiguous, two copies of Animal
class Animal {
public:
    void breathe() { cout << "Breathing" << endl; }
};

// Use 'virtual' to share a single Animal base
class Dog : virtual public Animal {
public:
    void bark() { cout << "Woof!" << endl; }
};

class Cat : virtual public Animal {
public:
    void meow() { cout << "Meow!" << endl; }
};

class DogCat : public Dog, public Cat {
public:
    void speak() { bark(); meow(); }
};

int main() {
    DogCat dc;
    dc.breathe();  // unambiguous "” only ONE Animal base
    dc.speak();

    // Without 'virtual' above, dc.breathe() would be ambiguous:
    // error: request for member 'breathe' is ambiguous

    return 0;
}

The final Keyword

Use final (C++11) to prevent a class from being inherited further, or to prevent a virtual function from being overridden in derived classes.

final Class and final Method
#include <iostream>
using namespace std;

class Base {
public:
    virtual void greet() { cout << "Hello from Base" << endl; }
};

class Derived : public Base {
public:
    // final on a method "” no further override allowed
    void greet() override final {
        cout << "Hello from Derived (final)" << endl;
    }
};

// class MoreDerived : public Derived {
//     void greet() override { }  // ERROR: greet is final
// };

// final on a class "” cannot be inherited
class Sealed final : public Base {
public:
    void greet() override { cout << "Sealed class" << endl; }
};

// class Child : public Sealed { };  // ERROR: Sealed is final

int main() {
    Derived d;
    d.greet();  // Hello from Derived (final)

    Sealed s;
    s.greet();  // Sealed class

    return 0;
}

Types of Inheritance "” Summary

TypeDescriptionExample
SingleOne derived class inherits from one base classDog : Animal
MultilevelChain of inheritance: A → B → CElectricCar : Car : Vehicle
MultipleOne class inherits from two or more base classesDuck : Flyable, Swimmable
HierarchicalMultiple classes inherit from one base classDog, Cat, Bird : Animal
HybridCombination of multiple inheritance typesMix of above (use virtual inheritance)

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.