Lesson content
Read, practise, then check your understanding
Inheritance models an is-a relationship. A derived class receives accessible behavior from a base class, then adds or specializes what it needs. Use it when objects genuinely share a common contract—not simply to avoid writing a few lines twice.
Create a base and derived class
#include <iostream>
class Shape {
public:
virtual double area() const = 0;
virtual ~Shape() = default;
};
class Rectangle : public Shape {
private:
double width;
double height;
public:
Rectangle(double w, double h) : width(w), height(h) {}
double area() const override {
return width * height;
}
};
Rectangle publicly inherits from Shape. The pure virtual function (= 0) makes Shape an abstract class: it defines a contract but cannot be instantiated directly.
Runtime polymorphism
A base reference or pointer can work with any derived object. The virtual keyword ensures the derived override runs.
void printArea(const Shape& shape) {
std::cout << shape.area();
}
Rectangle card(4.0, 3.0);
printArea(card); // 12
Add override in the derived class. The compiler will then catch signature mistakes that would otherwise create a different function.
Access levels
publicmembers are available to all callers.protectedmembers are available to the class and its derived classes.privatemembers remain inside the declaring class (and its friends).
Prefer private data with protected or public functions. Giving derived classes direct access to state makes invariants harder to protect.
Inheritance shapes
Single inheritance gives one derived class one direct base. Multilevel inheritance extends a chain such as Widget → Button → IconButton. Hierarchical inheritance gives several derived types one base, such as Circle and Rectangle implementing Shape. Multiple inheritance gives a class more than one direct base and works best for small independent interfaces.
struct Printable { virtual void print() const = 0; virtual ~Printable() = default; };
struct Savable { virtual void save() const = 0; virtual ~Savable() = default; };
class Report final : public Printable, public Savable {
public:
void print() const override { /* render */ }
void save() const override { /* persist */ }
};
When two inheritance paths contain the same base, the diamond can create duplicate base subobjects. Virtual inheritance (class Left : virtual public Root) makes the most-derived object share one virtual base, but complicates construction and layout. Prefer composition unless shared identity or a true substitutable interface requires inheritance.
Public inheritance models is-a and preserves the base public interface. Protected or private inheritance changes accessibility and is usually less clear than holding a member. Constructors are not automatically inherited unless exposed with using Base::Base; base construction occurs before members and derived construction.
Design guidance
A polymorphic base class should usually have a virtual destructor. This ensures deleting a derived object through a base pointer destroys the complete object safely.
Before choosing inheritance, ask whether composition is clearer: a Car has an Engine, so an engine member is more natural than Car : Engine.
Knowledge check
Answer every question correctly to complete this chapter.
0 of 10 checks passed
Your progress is saved on this device.