- Create a derived class and call the base class constructor
- Override methods with
virtualandoverride - Explain how polymorphism works through base pointers and references
- Create an abstract class with pure virtual functions
A game has a warrior, a mage and an archer. All of them have a name and health, and all of them attack — but each in its own way. Instead of repeating the same code in three classes, you can write the common part once in a base class and put the differences into derived classes. That is inheritance. Polymorphism then lets you treat them all the same way: you say “attack!”, and each character attacks in its own style.
Inheritance
class Warrior : public Character means “Warrior derives from Character”. The derived class receives all members of the base class and can add its own. protected members of the base class are closed to outside code but visible to derived classes. The derived class's constructor calls the base constructor in its initializer list.
#include <iostream>
#include <string>
class Character {
public:
Character(const std::string& name, int health)
: name_(name), health_(health) {}
void status() const {
std::cout << name_ << " has " << health_ << " HP\n";
}
protected:
std::string name_;
int health_;
};
class Warrior : public Character {
public:
Warrior(const std::string& name) : Character(name, 150) {}
void shieldUp() {
health_ += 20;
std::cout << name_ << " raises a shield\n";
}
};
int main() {
Warrior w("Elvin");
w.status();
w.shieldUp();
w.status();
return 0;
}Elvin has 150 HP Elvin raises a shield Elvin has 170 HP
status() comes ready-made from the base class, while shieldUp() exists only in Warrior.Virtual functions
A derived object can be reached through a base class reference or pointer: every warrior is also a character. But which method is called then? For an ordinary method — the base class version, because the choice is made at compile time from the type of the reference. If the method is declared virtual, the choice is made while the program runs, based on the object's actual type.
#include <iostream>
class Base {
public:
virtual ~Base() = default;
void hello() const { std::cout << "Base::hello\n"; }
virtual void greet() const { std::cout << "Base::greet\n"; }
};
class Derived : public Base {
public:
void hello() const { std::cout << "Derived::hello\n"; }
void greet() const override { std::cout << "Derived::greet\n"; }
};
int main() {
Derived d;
const Base& ref = d;
ref.hello();
ref.greet();
return 0;
}Base::hello Derived::greet
hello is not virtual, so the reference type (Base) decides; greet is virtual, so the object's actual type (Derived) decides.Abstract classes and polymorphism
Sometimes the base class does not know how to perform a method: “the area of a shape” cannot be computed in general. Such a method is declared pure virtual with = 0. A class with at least one pure virtual method is abstract: you cannot create objects of it, only derive from it. Then we can keep different shapes in one vector and treat them all the same way:
#include <iostream>
#include <memory>
#include <vector>
class Shape {
public:
virtual ~Shape() = default;
virtual int area() const = 0;
};
class Rect : public Shape {
public:
Rect(int w, int h) : w_(w), h_(h) {}
int area() const override { return w_ * h_; }
private:
int w_, h_;
};
class Triangle : public Shape {
public:
Triangle(int b, int h) : b_(b), h_(h) {}
int area() const override { return b_ * h_ / 2; }
private:
int b_, h_;
};
int main() {
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Rect>(4, 3));
shapes.push_back(std::make_unique<Triangle>(6, 5));
int total = 0;
for (const auto& s : shapes) {
std::cout << "Area: " << s->area() << '\n';
total += s->area();
}
std::cout << "Total: " << total << '\n';
return 0;
}Area: 12 Area: 15 Total: 27
Shape it has, yet each object calls its own area() — that is polymorphism.| Term | Meaning |
|---|---|
| base class | the class holding the common part (Shape) |
| derived class | a class that derives from the base and extends it (Rect) |
virtual | the method is chosen by the object's actual type |
override | asks the compiler to check that a virtual method is overridden |
= 0 | a pure virtual method; the class becomes abstract |
Key points
class B : public A—Bderives fromAand receives its members.protectedmembers are visible to derived classes but not to outside code.- A
virtualmethod called through a base reference or pointer is chosen by the object's actual type. overridecatches mistakes at compile time; a polymorphic base needs avirtualdestructor.- A pure virtual method (
= 0) makes a class abstract: no objects can be created from it.
Check yourself
10 questions. Every correct answer earns XP.
Archer from Character?