C++ tutorials  /  Inheritance in C++
Chapter 12 · C++

Inheritance in C++

Inheritance in C++ is an OOP mechanism that allows a new class (called the derived or child class) to acquire the properties (data members) and behaviors (member functions) of an existing class (called the base or parent class), establishing an 'is-a' relationship between them. Inheritance promotes code reuse by letting common functionality be defined once in a base class and automatically shared by all derived classes, which can also add their own unique members or override inherited behavior.

Think of inheritance like genetic traits passed from parent to child — a child inherits characteristics like eye color and height from their parents automatically, without needing to redefine them, but the child can also have their own unique traits the parents didn't have. In C++, if you have a general 'Vehicle' class with common traits like speed and fuel, a 'Car' class can 'inherit' from 'Vehicle' to automatically get those same traits and behaviors, while also adding car-specific features like 'numberOfDoors' — without rewriting the shared logic that already exists in 'Vehicle'.

In a company's HR software, a general 'Employee' base class defines shared attributes like name, ID, and salary, and common behavior like calculatePay(). Specific derived classes like 'Manager' and 'Engineer' inherit all of this automatically, while each adds its own unique attributes — 'Manager' might add 'teamSize', and 'Engineer' might add 'programmingLanguage' — without duplicating the shared employee logic in each class. In a game like Fortnite, a base 'Weapon' class defines shared behavior like reload() and fire(), while derived classes like 'AssaultRifle', 'Shotgun', and 'SniperRifle' each inherit that shared framework but override fire() with their own unique firing behavior and add their own specific stats like scope zoom or spread pattern.

Without inheritance, every class that shares common attributes and behavior with another would need to duplicate that shared code entirely, leading to massive code repetition — if a bug is found in the shared logic, it would need to be fixed in every single duplicated copy across the codebase. Inheritance lets developers define shared functionality exactly once in a base class, automatically propagate it to every derived class, and update it in a single place when changes are needed, while still allowing each derived class the flexibility to specialize or override specific behaviors — a critical feature for building large, extensible, and maintainable class hierarchies that mirror real-world categorization (like Animal → Mammal → Dog).

  • Single Inheritance: The simplest and most common form, where a derived class inherits from exactly one base class (e.g., 'Dog' inherits from 'Animal'), establishing a straightforward one-to-one parent-child relationship.
  • Multiple Inheritance: A derived class inherits from two or more base classes simultaneously (e.g., 'FlyingCar' inheriting from both 'Car' and 'Airplane'), a feature C++ supports (unlike many other OOP languages like Java) but which requires careful handling to avoid ambiguity issues like the 'diamond problem'.
  • Multilevel Inheritance: A chain of inheritance where a class derives from another derived class, forming a hierarchy of more than two levels (e.g., 'Animal' → 'Mammal' → 'Dog'), with each level inheriting all accumulated members from every class above it in the chain.
  • Hierarchical Inheritance: Multiple derived classes all inherit from the SAME single base class (e.g., 'Car', 'Truck', and 'Motorcycle' all inheriting from a common 'Vehicle' base class), allowing multiple related but distinct classes to share common functionality.
  • Hybrid Inheritance: A combination of two or more types of inheritance (e.g., combining hierarchical and multiple inheritance) within the same class hierarchy, which can introduce complex ambiguity issues like the diamond problem, typically resolved in C++ using 'virtual inheritance'.
// Base class class BaseClass { public: void baseMethod() { /* ... */ } }; // Derived class using public inheritance class DerivedClass : public BaseClass { public: void derivedMethod() { /* ... */ } }; // Constructor chaining (calling base constructor from derived) class DerivedClass2 : public BaseClass { public: DerivedClass2(int x) : BaseClass(x) { // derived class constructor body } }; // Multiple inheritance class Derived : public Base1, public Base2 { // inherits from both Base1 and Base2 };
A developer building a vehicle rental system has a general 'Vehicle' class with shared attributes (brand, rentalPricePerDay) and behavior (calculateRentalCost()), and needs to create 'Car' and 'Motorcycle' classes that reuse this shared logic through inheritance rather than duplicating it, while each also adding its own unique attributes and correctly initializing the inherited base class portion through constructor chaining.
Single Inheritance with Constructor Chaining
Demonstrates a derived class inheriting from a base class, reusing its data and behavior, while properly initializing the base portion using the constructor initializer list.
cpp
#include <iostream> using namespace std; class Vehicle { protected: string brand; double rentalPricePerDay; public: Vehicle(string b, double price) { brand = b; rentalPricePerDay = price; } double calculateRentalCost(int days) { return rentalPricePerDay * days; } }; class Car : public Vehicle { private: int numberOfDoors; public: Car(string b, double price, int doors) : Vehicle(b, price) { numberOfDoors = doors; } void display() { cout << brand << " (" << numberOfDoors << " doors)" << endl; } }; int main() { Car myCar("Toyota", 45.0, 4); myCar.display(); cout << "5-day rental cost: $" << myCar.calculateRentalCost(5) << endl; return 0; }
Toyota (4 doors) 5-day rental cost: $225
'Car' inherits from 'Vehicle' using 'public' inheritance, automatically gaining access to 'brand', 'rentalPricePerDay' (declared 'protected', so accessible in the derived class), and the 'calculateRentalCost()' method without redefining any of it. The 'Car' constructor uses ': Vehicle(b, price)' to explicitly call the base class's constructor first, properly initializing the inherited portion, before initializing its own unique 'numberOfDoors' member.
Hierarchical Inheritance with Multiple Derived Classes
Shows two different derived classes both inheriting independently from the same base class, each adding their own specialization.
cpp
#include <iostream> using namespace std; class Vehicle { protected: string brand; public: Vehicle(string b) : brand(b) {} void honk() { cout << brand << " says: Beep beep!" << endl; } }; class Car : public Vehicle { public: Car(string b) : Vehicle(b) {} }; class Motorcycle : public Vehicle { public: Motorcycle(string b) : Vehicle(b) {} }; int main() { Car car("Honda Civic"); Motorcycle bike("Harley Davidson"); car.honk(); bike.honk(); return 0; }
Honda Civic says: Beep beep! Harley Davidson says: Beep beep!
Both 'Car' and 'Motorcycle' independently inherit from the SAME 'Vehicle' base class, each getting their own separate access to the shared 'honk()' method and 'brand' member without duplicating that logic in either derived class — this is hierarchical inheritance, where one base class serves multiple distinct derived classes.
  • Using private Inheritance When public Inheritance Was Intended: Writing 'class Derived : Base' without specifying an inheritance access specifier defaults to 'private' inheritance for a 'class' (unlike 'struct', which defaults to 'public'), which makes all inherited public/protected members of the base class become private in the derived class — often not what beginners intend, breaking expected access patterns like calling inherited methods from outside the derived class.
  • Trying to Access Private Base Class Members Directly from a Derived Class: Members declared 'private' in the base class are NOT accessible directly in derived classes, even with 'public' inheritance — only 'protected' and 'public' base class members are accessible in derived classes. Beginners often mistakenly make base class members 'private' when they actually need derived classes to access them directly, and should use 'protected' instead.
  • Forgetting That Base Class Constructors Are Not Automatically Inherited: A derived class does not automatically inherit its base class's constructors (unless explicitly using 'using BaseClass::BaseClass;' in C++11+) — the derived class must define its own constructor(s), which should explicitly call an appropriate base class constructor via the initializer list if the base class requires specific initialization parameters.
  • The Diamond Problem with Multiple Inheritance: When a class inherits from two base classes that both inherit from a common ancestor class, the derived class ends up with two separate copies of the common ancestor's members, causing ambiguity when accessing them (the compiler doesn't know which copy to use). This classic issue, known as the 'diamond problem', requires using 'virtual inheritance' on the intermediate base classes to ensure only a single shared copy of the common ancestor exists.
  • Not Understanding the Order of Constructor and Destructor Calls in Inheritance: Beginners sometimes assume the derived class's constructor runs before the base class's constructor, when in fact C++ always calls the BASE class constructor FIRST (before the derived class constructor body executes), and destructors run in the exact opposite order (derived class destructor first, then base class destructor), which matters when there's dependent initialization logic between the two.
  • Use protected (Not private) for Base Class Members That Derived Classes Need Direct Access To: If derived classes genuinely need direct access to certain base class data members (not just through public getter/setter methods), declare those members 'protected' rather than 'private', since 'private' members are completely inaccessible to derived classes regardless of the inheritance type used.
  • Always Explicitly Specify public Inheritance Unless private/protected Inheritance Is Specifically Intended: Write 'class Derived : public Base' explicitly, since the default (private inheritance for classes) is rarely what's intended and can cause confusing access errors; public inheritance correctly models the common 'is-a' relationship most beginners are trying to express.
  • Favor Composition Over Multiple Inheritance When Possible: While C++ supports multiple inheritance, it introduces significant complexity (like the diamond problem) that can make class hierarchies fragile and hard to reason about — where possible, prefer composition (embedding objects of other classes as members) to achieve similar code reuse goals with a simpler, more predictable structure.
  • Use Virtual Inheritance to Resolve the Diamond Problem When Multiple Inheritance Is Necessary: When a hybrid inheritance hierarchy genuinely requires multiple base classes that share a common ancestor, declare the shared base class as 'virtual' in the intermediate classes (e.g., 'class B : virtual public A') to ensure only one shared instance of the common ancestor's members exists in the final derived class, eliminating ambiguity.
What is the difference between public, protected, and private inheritance in C++?
With 'public' inheritance, the base class's public members remain public and protected members remain protected in the derived class (the most common form, modeling a true 'is-a' relationship). With 'protected' inheritance, both the base class's public and protected members become protected in the derived class. With 'private' inheritance, both public and protected base class members become private in the derived class, meaning they're only accessible within the derived class itself and not further inherited or accessed from outside — private inheritance is used far less often and typically models an 'implemented-in-terms-of' relationship rather than a true 'is-a' relationship.
Why can't a derived class access private members of its base class directly, and how can this be addressed if needed?
Private members are intentionally restricted to be accessible only within the exact class they're declared in, as a core principle of encapsulation — this restriction applies regardless of inheritance, since allowing derived classes automatic access to private members would undermine the base class's ability to fully control and protect its own internal state. If a derived class genuinely needs direct access to certain base class data, the base class should declare those specific members as 'protected' instead of 'private', which grants derived classes direct access while still hiding those members from unrelated outside code.
What is the 'diamond problem' in C++ multiple inheritance, and how is it resolved?
The diamond problem occurs when a class inherits from two base classes that both, in turn, inherit from the same common ancestor class — without any special handling, the final derived class ends up containing two separate, duplicate copies of the common ancestor's members, causing ambiguity errors when the compiler can't determine which copy an access refers to. It's resolved in C++ using 'virtual inheritance', where the intermediate base classes inherit from the common ancestor using the 'virtual' keyword (e.g., 'class B : virtual public A'), ensuring the final derived class contains only a single, shared instance of the common ancestor's members regardless of how many paths lead to it.
In what order are base and derived class constructors and destructors called during object creation and destruction?
During object creation, the BASE class's constructor always executes FIRST, fully initializing the inherited portion of the object, before the DERIVED class's constructor body executes to initialize its own additional members — this ensures the base portion is always fully valid before the derived class attempts to build on top of it. During destruction, the order is exactly reversed: the DERIVED class's destructor executes first, cleaning up derived-specific resources, followed by the BASE class's destructor, cleaning up the inherited portion — following a logical 'last acquired, first released' pattern.
Does a derived class automatically inherit the constructors of its base class in C++?
No, by default a derived class does NOT automatically inherit its base class's constructors — the derived class must define its own constructor(s), and if the base class requires parameters for proper initialization, the derived class's constructor must explicitly invoke the appropriate base class constructor via the member initializer list (e.g., 'Derived(int x) : Base(x) {}'). However, C++11 introduced the 'using Base::Base;' syntax, which can be used inside a derived class to explicitly bring in and reuse the base class's constructors, reducing boilerplate when the derived class doesn't need to add any additional initialization logic of its own.
Create a base class 'Shape' with a protected 'name' member and a method 'describe()', then derive a 'Circle' class that adds a 'radius' member and a method to calculate its area, using constructor chaining to initialize the inherited name.
#include <iostream> using namespace std; class Shape { protected: string name; public: Shape(string n) : name(n) {} void describe() { cout << "This is a " << name << endl; } }; class Circle : public Shape { private: double radius; public: Circle(double r) : Shape("Circle"), radius(r) {} double area() { return 3.14159 * radius * radius; } }; int main() { Circle c(5.0); c.describe(); cout << "Area: " << c.area() << endl; return 0; }
Demonstrate hierarchical inheritance by creating a base class 'Animal' with a method 'eat()', and two derived classes 'Bird' (adding 'fly()') and 'Fish' (adding 'swim()').
#include <iostream> using namespace std; class Animal { public: void eat() { cout << "This animal eats food." << endl; } }; class Bird : public Animal { public: void fly() { cout << "This bird flies." << endl; } }; class Fish : public Animal { public: void swim() { cout << "This fish swims." << endl; } }; int main() { Bird b; Fish f; b.eat(); b.fly(); f.eat(); f.swim(); return 0; }
Predict the output and explain the order of execution: class A { public: A() { cout << "A constructor\n"; } ~A() { cout << "A destructor\n"; } }; class B : public A { public: B() { cout << "B constructor\n"; } ~B() { cout << "B destructor\n"; } }; int main() { B obj; return 0; }
The output is: A constructor B constructor B destructor A destructor When 'B obj;' is created, the base class 'A's constructor runs FIRST automatically (initializing the inherited portion), followed by 'B's own constructor. When 'obj' goes out of scope at the end of main(), destructors run in the EXACT REVERSE order — 'B's destructor executes first (cleaning up derived-specific resources), followed by 'A's destructor (cleaning up the base portion), following the logical last-acquired-first-released pattern.

Inheritance allows C++ classes to reuse and extend functionality from existing classes, modeling natural 'is-a' relationships and dramatically reducing code duplication across related classes. Understanding the different inheritance types (single, multiple, multilevel, hierarchical, hybrid), the effects of access specifiers (public/protected/private) on inherited members, proper constructor chaining, and the correct order of constructor/destructor calls are essential for building clean, extensible class hierarchies. While powerful, features like multiple inheritance require careful handling of issues like the diamond problem, and inheritance itself should always be used to model genuine 'is-a' relationships rather than misapplied wherever code reuse is desired.

© 2026 CompileX. Maintained by Aditya Kumar Sharma.