๐ WAYPOINT LESSON
Virtual Functions and Polymorphism
โญโญ intermediateโณ 30 min read๐ Lesson 84 of 204
Dynamic dispatch through base pointers, abstract classes, and why by-value storage breaks polymorphism.
Polymorphism: through a base-class reference or pointer, the right override for the actual object runs โ chosen at run time via the virtual table.
#include <iostream>
#include <memory>
#include <vector>
class Shape {
public:
virtual ~Shape() = default;
virtual double area() const = 0; // pure virtual
virtual const char* name() const = 0;
};
class Square : public Shape {
public:
explicit Square(double s) : side_{s} {}
double area() const override { return side_ * side_; }
const char* name() const override { return "square"; }
private:
double side_;
};
class Circle : public Shape {
public:
explicit Circle(double r) : radius_{r} {}
double area() const override { return 3.14159265358979 * radius_ * radius_; }
const char* name() const override { return "circle"; }
private:
double radius_;
};
double total_area(const std::vector<std::unique_ptr<Shape>>& shapes) {
double sum = 0;
for (const auto& s : shapes) sum += s->area(); // dynamic dispatch per element
return sum;
}
The two conditions for dynamic dispatch
- The call goes through a reference or pointer to the base.
- The function is virtual in the base.
Call by value slices the object (a Shape copy of a Square loses the
derived parts) and dispatch never happens. Store shapes by pointer (a smart
pointer, Module 8) or reference, never by value, in polymorphic containers.
Pure virtual and abstract types
area() const = 0 makes Shape abstract: it cannot be instantiated, only
derived from. Derived classes must override every pure virtual or stay
abstract. This is how C++ expresses "interface".
โก Now practice
Ready to CodePolymorphism and the virtual destructor ruleAbstract shapes with real dispatch, and a challenge that fails without a virtual destructor.
3 challenges ยท ยท ~35 min