C++ Polymorphism and Virtual Functions
Polymorphism means one call, many behaviors. In C++ it needs virtual functions and a base pointer or reference.
#include <iostream>
#include <memory>
#include <numbers>
#include <vector>
class Shape {
public:
virtual ~Shape() = default; // a virtual destructor
virtual double area() const { return 0; }
};
class Circle : public Shape {
public:
explicit Circle(double r) : r(r) {}
double area() const override { return std::numbers::pi * r * r; }
private:
double r;
};
class Rectangle : public Shape {
public:
Rectangle(double w, double h) : w(w), h(h) {}
double area() const override { return w * h; }
private:
double w, h;
};
int main() {
std::vector<std::unique_ptr<Shape>> shapes;
shapes.push_back(std::make_unique<Circle>(2));
shapes.push_back(std::make_unique<Rectangle>(3, 4));
double total = 0;
for (const auto& s : shapes) {
std::cout << s->area() << '\n'; // the real object decides
total += s->area();
}
std::cout << "Total: " << total << '\n';
}
12.5664
12
Total: 24.5664
virtual, override and final
virtualin the base: the function can be replaced, and the call is decided when the program runs.overridein the derived class: the compiler checks that you really replace a base function.final: no more overriding (or no more derived classes).
struct Base {
virtual void run() const {}
};
struct Derived : Base {
void run() override {} // missing const: this is not an override, the compiler tells you
};
int main() { }
Override.cpp:6:10: error: 'void Derived::run()' marked 'override', but does not override
6 | void run() override {} // missing const: this is not an override, the compiler tells you
| ^~~
Override.cpp:2:18: warning: 'virtual void Base::run() const' was hidden [-Woverloaded-virtual=]
2 | virtual void run() const {}
| ^~~
Override.cpp:6:10: note: by 'void Derived::run()'
6 | void run() override {} // missing const: this is not an override, the compiler tells you
| ^~~
Without virtual: no polymorphism
#include <iostream>
struct Animal { void sound() const { std::cout << "...\n"; } };
struct Dog : Animal { void sound() const { std::cout << "Woof\n"; } };
int main() {
Dog d;
Animal& a = d;
a.sound(); // calls Animal::sound: the function is not virtual
}
…
Object slicing
If you copy a derived object into a base object (not a pointer or reference), the derived part is cut off:
#include <iostream>
struct Base { virtual const char* name() const { return "Base"; } };
struct Derived : Base { const char* name() const override { return "Derived"; } };
void by_value(Base b) { std::cout << b.name() << '\n'; }
void by_reference(const Base& b) { std::cout << b.name() << '\n'; }
int main() {
Derived d;
by_value(d); // sliced
by_reference(d); // polymorphic
}
Base
Derived
The virtual destructor
If you delete a derived object through a base pointer and the base destructor is not virtual, the derived destructor does not run (undefined behavior). A class with virtual functions should have a virtual destructor.
| Exercises & Assignments |
|---|
| No Content Found. |
| Interview Questions & Answers |
|---|
| No Content Found. |