53 Intermediate The Hundred
The Override That Was Not
one keyword short of polymorphism
#include <iostream>
struct Shape {
virtual ~Shape() = default;
virtual void draw() const { std::cout << "[unnamed shape]\n"; }
};
struct Circle : Shape {
void draw() { std::cout << "( o )\n"; }
};
void render(const Shape& s) { s.draw(); }
int main() {
Circle c;
c.draw();
render(c); // the same circle, one line later... right?
}
Run it. What does it print?
Answer
( o ), then [unnamed shape] — one circle, drawn twice, two different pictures.
Why¶
An override must match the base declaration exactly, and const is part of a member
function's signature: void draw() and void draw() const are two different functions.
So Circle::draw() overrides nothing — it declares a new function that merely hides
the base one, while the vtable slot for Shape::draw() const still holds Shape's body.
Lookup on c.draw() finds the new function and stops; a call through any base handle —
Shape&, Shape*, a container of them — takes the untouched slot. -Wall -Wextra is
silent, and so is -Wsuggest-override (it fires only on functions that genuinely do
override, so you get it after the fix, never before); -Woverloaded-virtual catches it:
The fix¶
Match the signature, and write override (C++11) so the compiler checks you:
Both lines now print ( o ). Had override been there all along, the build would fail:
Takeaway: overriding is signature matching — override makes a typo a compile error.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo — then add -Woverloaded-virtual