C++ Inheritance Explained: Base Classes, Derived Classes, and How It Works
In real life, a Car is a Vehicle. A Dog is an Animal. A Manager is an Employee. These “is-a” relationships are exactly what inheritance models in C++ — letting you build a new class on top of an existing one instead of starting from scratch every time.
The Basic Syntax
To make one class inherit from another, you use a colon followed by an access specifier and the base class name:
class DerivedClass : public BaseClass {
// ...
};
Here’s a complete example:
#include <iostream>
#include <string>
class Animal {
public:
std::string name;
void eat() {
std::cout << name << " is eating.\n";
}
};
class Dog : public Animal {
public:
void bark() {
std::cout << name << " says: Woof!\n";
}
};
int main() {
Dog d;
d.name = "Rex";
d.eat(); // inherited from Animal
d.bark(); // defined in Dog
return 0;
}
Output:
Rex is eating.
Rex says: Woof!
Dog automatically gets the name member and the eat() method from Animal. You didn’t have to rewrite them.
Constructor Chaining
When you create a derived object, the base class constructor runs first, then the derived class constructor. You pass arguments to the base constructor using an initializer list:
#include <iostream>
#include <string>
class Employee {
public:
std::string name;
int id;
Employee(std::string n, int i) : name(n), id(i) {}
void display() {
std::cout << "Employee: " << name << " (ID: " << id << ")\n";
}
};
class Manager : public Employee {
public:
std::string department;
Manager(std::string n, int i, std::string dept)
: Employee(n, i), department(dept) {}
void displayManager() {
display();
std::cout << "Department: " << department << "\n";
}
};
int main() {
Manager m("Alice", 101, "Engineering");
m.displayManager();
return 0;
}
Output:
Employee: Alice (ID: 101)
Department: Engineering
Manager calls Employee(n, i) in its initializer list to set up the base portion of the object.
Access Specifiers: What Gets Inherited?
Three access levels control what a derived class can see:
| Base member | public inheritance | protected inheritance | private inheritance |
|---|---|---|---|
public | public | protected | private |
protected | protected | protected | private |
private | not accessible | not accessible | not accessible |
For most beginner code, use public inheritance. The key practical rule is: private members of the base class are never directly accessible in the derived class, even though they exist inside the object.
class Base {
private:
int secret = 42; // derived cannot access this directly
protected:
int shared = 10; // derived can access this
public:
int open = 99; // anyone can access this
};
class Derived : public Base {
public:
void show() {
// std::cout << secret; // error — private
std::cout << shared; // fine — protected
std::cout << open; // fine — public
}
};
Overriding Methods
A derived class can replace a base class method with its own version. Use the virtual keyword in the base and override in the derived class:
#include <iostream>
class Shape {
public:
virtual void draw() {
std::cout << "Drawing a generic shape.\n";
}
};
class Circle : public Shape {
public:
void draw() override {
std::cout << "Drawing a circle.\n";
}
};
class Square : public Shape {
public:
void draw() override {
std::cout << "Drawing a square.\n";
}
};
int main() {
Shape* s1 = new Circle();
Shape* s2 = new Square();
s1->draw(); // Drawing a circle.
s2->draw(); // Drawing a square.
delete s1;
delete s2;
return 0;
}
This is runtime polymorphism — the right version of draw() is called based on the actual object type, not the pointer type. For a deeper look at this mechanism, see the virtual functions article.
Types of Inheritance
C++ supports several forms of inheritance:
- Single inheritance — one base class (the examples above)
- Multilevel inheritance —
Cinherits fromB, which inherits fromA - Multiple inheritance — one class inherits from two base classes
Multiple inheritance is powerful but can create complexity (the “diamond problem”). Beginners should start with single and multilevel inheritance.
// Multilevel example
class A { public: void hello() { std::cout << "Hello from A\n"; } };
class B : public A {};
class C : public B {};
int main() {
C obj;
obj.hello(); // inherited all the way from A
return 0;
}
Related Articles
- OOP in C++: Inheritance, Encapsulation, and Polymorphism Explained
- C++ Classes and Objects: A Beginner’s Guide to OOP
- Virtual Functions and Polymorphism in C++ Explained
- C++ Constructors and Destructors Explained
Take Your C++ Further
If you’re looking to go deeper with C++, the C++ Better Explained Ebook is perfect for you — whether you’re a complete beginner or looking to solidify your understanding. Just $19.