Skip to content

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:

warning: ‘virtual void Shape::draw() const’ was hidden [-Woverloaded-virtual]

The fix

Match the signature, and write override (C++11) so the compiler checks you:

struct Circle : Shape {
    void draw() const override { std::cout << "( o )\n"; }
};

Both lines now print ( o ). Had override been there all along, the build would fail:

error: ‘void Circle::draw()’ marked ‘override’, but does not override

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

Open in Compiler Explorer ↗ Quiz this entry