Inheritance & Polymorphism
Inheritance
Reuse and extend classes: base and derived classes, public/protected/private inheritance, the five types of inheritance, constructor order, and the diamond problem.
Inheritance lets a new class (the derived or child class) take on the members of an existing class (the base or parent class), then add its own or change some. It models an is-a relationship and avoids writing the same code twice.
#include <iostream>
#include <string>
using namespace std;
class Person { // base class
protected:
string name;
int age;
public:
Person(const string &n, int a) : name(n), age(a) {}
void introduce() const { cout << "I am " << name << ", " << age << " years old." << endl; }
};
class Student : public Person { // Student is-a Person
string course;
public:
Student(const string &n, int a, const string &c) : Person(n, a), course(c) {}
void study() const { cout << name << " is studying " << course << "." << endl; } // can use protected name
};
int main() {
Student s("Asha", 19, "Data Structures");
s.introduce(); // inherited from Person
s.study(); // Student's own
return 0;
}I am Asha, 19 years old. Asha is studying Data Structures.
Access in derived classes
A derived class can use the base's public and protected members, but never its private ones. The mode of inheritance (public, protected, private) then decides how inherited members appear to the outside world:
| Base member | public inheritance |
protected inheritance |
private inheritance |
|---|---|---|---|
public |
public | protected | private |
protected |
protected | protected | private |
private |
not accessible | not accessible | not accessible |
public inheritance is by far the most common — it is the one that means "is-a".
Types of inheritance
| Type | Shape | Example |
|---|---|---|
| Single | one base → one derived | Car : Vehicle |
| Multilevel | chain: A → B → C | Vehicle → Car → ElectricCar |
| Multiple | one class, several bases | SmartPhone : Phone, Camera |
| Hierarchical | one base, several derived | Shape → Circle, Square, Triangle |
| Hybrid | a mix of the above | multiple + multilevel together |
Multilevel inheritance and constructor order
Constructors run from the base down to the most derived class; destructors run in the reverse order.
#include <iostream>
using namespace std;
class Vehicle {
public:
Vehicle() { cout << "Vehicle constructor" << endl; }
~Vehicle() { cout << "Vehicle destructor" << endl; }
};
class Car : public Vehicle {
public:
Car() { cout << " Car constructor" << endl; }
~Car() { cout << " Car destructor" << endl; }
};
class ElectricCar : public Car {
public:
ElectricCar() { cout << " ElectricCar constructor" << endl; }
~ElectricCar() { cout << " ElectricCar destructor" << endl; }
};
int main() {
ElectricCar tesla;
cout << "--- object in use ---" << endl;
return 0;
}Vehicle constructor
Car constructor
ElectricCar constructor
--- object in use ---
ElectricCar destructor
Car destructor
Vehicle destructorMultiple inheritance
#include <iostream>
using namespace std;
class Camera {
public:
void takePhoto() const { cout << "Click! Photo saved." << endl; }
};
class Phone {
public:
void call(const char *who) const { cout << "Calling " << who << "..." << endl; }
};
class SmartPhone : public Phone, public Camera { // two bases
public:
void browse() const { cout << "Opening browser." << endl; }
};
int main() {
SmartPhone p;
p.call("Mom");
p.takePhoto();
p.browse();
return 0;
}Calling Mom... Click! Photo saved. Opening browser.
The diamond problem and virtual base classes
In hybrid inheritance, a class can inherit the same base twice:
Without help, TA would contain two copies of Person, and ta.name would be ambiguous. Declaring the shared base virtual makes the derived classes share one copy:
#include <iostream>
#include <string>
using namespace std;
class Person {
public:
string name;
Person(const string &n = "") : name(n) { cout << "Person(" << n << ")" << endl; }
};
class Student : virtual public Person { public: Student() { cout << "Student" << endl; } };
class Employee : virtual public Person { public: Employee() { cout << "Employee" << endl; } };
class TA : public Student, public Employee {
public:
TA(const string &n) : Person(n) { cout << "TA" << endl; } // the most derived class builds the shared base
};
int main() {
TA ta("Nikhil");
cout << "name = " << ta.name << " (only one Person inside)" << endl;
return 0;
}Person(Nikhil) Student Employee TA name = Nikhil (only one Person inside)
Overriding (redefining) base functions
A derived class can define a function with the same signature as the base, replacing its behaviour. The base version is still reachable with Base::function():
#include <iostream>
using namespace std;
class Account {
public:
double interestRate() const { return 3.0; }
};
class SeniorCitizenAccount : public Account {
public:
double interestRate() const { return Account::interestRate() + 0.5; } // reuse, then extend
};
int main() {
Account a;
SeniorCitizenAccount s;
cout << "regular: " << a.interestRate() << "%, senior: " << s.interestRate() << "%" << endl;
return 0;
}regular: 3%, senior: 3.5%
Without virtual, which version runs depends on the declared type of the pointer or reference — the problem that virtual functions solve.
Test yourself
4 questions · pick an answer to check it instantly
- 1
Can a derived class access its base class's
privatemembers directly?Private members are only accessible inside the class that declares them (and its friends). Useprotectedfor members derived classes need. - 2
With
class B : protected A, apublicmember of A becomes...Protected inheritance demotes public members to protected. - 3
Constructing an object of
CwhereC : BandB : Aruns constructors in which order?Base classes are constructed first; destructors run in the reverse order. - 4
What does a virtual base class prevent?
virtualinheritance makes all paths share a single base subobject.