Concepts / Understanding Explicit Function Overriding

Understanding Explicit Function Overriding

A derived function only overrides a base function when the base class has a virtual function with the same name, so a misspelled name does not get corrected and instead causes an error.

  • Programming

A Prediction Before the Explanation

Many learners assume that a small spelling mistake in a derived function's name is harmless. The reasoning goes like this: the derived class clearly meant to replace a function from its base class, so the language will probably work out the intended name and connect the two. Under that belief, a slightly misspelled name would be ignored or quietly corrected, and the program would behave as if the spelling were right. This belief is wrong, and it is one of the most frequent sources of confusion in class hierarchies.

What do you think happens?

A base class has a virtual function named draw. A derived class declares a function named drw, meaning it tried to override draw but misspelled it. When draw is called through a base-class reference, which function runs?

  • The derived drw function, because the derived class clearly meant to replace draw

  • The base draw function, because drw does not override anything

  • The compiler silently renames drw to draw and the derived version runs

Reveal answer
Answer:

The base draw function runs. The derived drw does not override anything, so it is simply a separate function that the base-class call never reaches.

Overriding depends on the base class having a virtual function with the same name. Because drw does not match draw, the derived class has no override, and the call made through the base reference still dispatches to the base version. The mismatch is not corrected by the language.

Why a Misspelled Name Is Not Corrected

Definition

A derived function overrides a base function only when the base class has a virtual function with the same name. A misspelled name does not get corrected. It becomes a declaration that does not line up with anything in the base class.

The key idea is that overriding is a matching relationship. The base class declares a virtual function, and the derived class supplies a replacement that is connected to it by name. When the name does not match, there is no connection. The derived class still compiles, because it is legal to add a new function with any name, but that new function is unrelated to the base function. Calls that go through the base class continue to reach the base version.

This is why the source describes the misspelled case as causing an error rather than a fix. The derived function is not promoted to an override. Its effect on the base-class interface is nothing at all, and the program's behavior is not what the author intended. The bug is silent: nothing in the declaration itself announces that anything went wrong.

Tracing a Call Through a Base Reference

Read the program below and follow the call one step at a time. The object is a Circle, but the variable that calls draw has the type Shape&, a reference to the base class. The question is which draw function the call reaches.

cpp
Output
Shape::draw
Notes on the code
  • Shape::draw is declared virtual, so it is the function that derived classes may override
  • Circle::drw has a different name, so it does not override Shape::draw
  • ref has type Shape&, so ref.draw() is a call made through the base-class interface
  • The output comes from the base version, because nothing in Circle replaces draw
Debugging

Trace the call step by step. Step 1: ref.draw() is looked up through the Shape interface. Step 2: Shape declares a virtual draw, so the call is eligible to reach a derived version. Step 3: Circle has no function called draw, only drw, so there is no derived replacement. Step 4: the call reaches Shape::draw, and the program prints Shape::draw. The drw function was written, compiled, and never called.

Comparing a Matching Name and a Misspelled Name

The two versions of the hierarchy differ by one letter, but they lead to opposite outcomes. The diagram below sets the matching case beside the misspelled case. In the matching case, the derived declaration connects to the base virtual function, so a call through the base reference reaches the derived code. In the misspelled case, the derived function is a separate function, and the base version runs.

Base draw()virtualBase draw()virtualDerived draw()overrides baseDerived drw()separate functionDerived version runsthrough base referenceBase version runsthrough base referencematched by namecall dispatchesno matchcall reaches
When the derived name matches the base virtual function, which function does a base-class call reach, and when does the derived version never run?

What the override Keyword Checks

The first safeguard against this silent failure is simply to state intent. The override keyword can be written on a declaration to say that the function is meant to override a base virtual function. The keyword does more than document intent, though. It asks the compiler to confirm that the declaration really does override a base virtual function, and it reports an error when that confirmation fails.

This turns a silent mistake into an immediate one. Without the keyword, a misspelled declaration compiles and the bug only appears later, when the wrong function runs. With the keyword, the same declaration is rejected as soon as it is compiled, at the point where the mistake was made. The diagram below shows the decision the compiler makes when it sees the keyword.

Declaration markedoverrideBase class has amatching virtualfunction?Declaration acceptedas overrideCompile-time errorreportedcheckyesno
What steps does the compiler take when it sees the override keyword, and at which step does it report an error?

Adding the override Keyword to a Mistyped Declaration

Take the same hierarchy as before and add the override keyword to the misspelled declaration. The before and after versions show how the outcome changes. The first version compiles and runs silently. The second version is rejected, because drw is marked as an override but does not override anything in the base class.

Before
class Circle : public Shape {
public:
    void drw() const {
        std::cout << "Circle::drw\n";
    }
};

Compiles. drw is a separate function, and ref.draw() prints Shape::draw.

After
class Circle : public Shape {
public:
    void drw() const override {
        std::cout << "Circle::drw\n";
    }
};

Compile-time error. drw is marked override, but nothing in Shape matches it.

Worked example

Correcting the Misspelled Declaration

The override keyword has rejected drw in Circle. Apply a correction so that Circle really overrides Shape::draw, then predict the output of the same main function.

  1. 1
    Read the compiler error

    The error says that drw is marked override but does not override a base function. This means the name has no match in Shape.

  2. 2
    Compare against the base declaration

    Shape declares virtual void draw() const. The name in the derived class must be draw, not drw.

  3. 3
    Correct the name

    Rename the derived function to draw and keep the same parameter list and const qualifier, so that the declaration lines up with the base function.

  4. 4
    Re-check the call

    With the name matching and override present, the compiler accepts the declaration. A call through Shape& now reaches the derived code.

Result

After the correction, the derived declaration is void draw() const override, and ref.draw() prints Circle::draw. The override keyword now confirms the connection instead of rejecting it.

cpp
Output
Circle::draw
Notes on the code
  • The name now matches the base virtual function draw
  • The const qualifier matches the base declaration
  • override asks the compiler to confirm the match

Common Overriding Mismatches

The misspelled name is only one of several ways a derived declaration can fail to line up with the base class. The source identifies the shared root cause as a declaration that does not match anything in the base class. The mistakes below all share that cause, and each one can be caught by the override keyword.

  • Common mistake

    Misspelling the derived function's name

    What it looks like

    Declaring drw in Circle when the base declares virtual void draw() const

    Why it fails

    The derived function never connects to the base virtual function, so base-class calls never reach it.

    Do this instead

    Use the exact base name draw and mark the declaration override.

  • Common mistake

    Dropping the const qualifier

    What it looks like

    Declaring void draw() override in Circle when the base declares virtual void draw() const

    Why it fails

    A declaration without the matching const qualifier does not line up with the base function, so it does not override it. With override present, the compiler reports an error.

    Do this instead

    Copy the full declaration from the base class, including the const qualifier, and keep override.

  • Common mistake

    Forgetting that the base function must be virtual

    What it looks like

    Base declares void draw() const without virtual, and Circle declares void draw() const override

    Why it fails

    The base function is not a virtual function, so there is nothing for the derived declaration to override. The override keyword reports the mismatch.

    Do this instead

    Declare the base function virtual, or remove override if no overriding is intended.

  • Common mistake

    Changing the parameter list

    What it looks like

    Base declares virtual void draw() const, and derived declares void draw(int scale) const override

    Why it fails

    The derived function has a different parameter list, so it is not the same function as the base function and does not override it.

    Do this instead

    Match the base parameter list exactly, or give the new function a different name if it is genuinely a new operation.

Where Overriding Fits in the Hierarchy

A class hierarchy connects a derived class to a base class. The derived class can replace behavior that the base class defines, and the overriding rules describe when that replacement counts. The source introduces a discussion of the benefits of hierarchies but does not spell out those benefits in the passage provided, so this article does not name them. What the surrounding material does establish is that the name-matching and override checks exist to keep the replacement honest: a derived function replaces a base behavior only when it is clearly connected to it.

Practice Predicting an Override Failure

EASY

A base class declares virtual void speak() const. A derived class declares void spek() const override. Without running the code, decide what the compiler does with the derived declaration, and then say which function a call such as ref.speak() would reach through a base reference.

Hints
  • Compare the derived name letter by letter with the base name.
  • The override keyword asks the compiler to confirm a match. What does it report when no match exists?
  • If the derived declaration is rejected, there is no derived version for a base-class call to reach.

Key Takeaways

  • A derived function overrides a base function only when the base class has a virtual function with the same name, so a misspelled name is not corrected and does not override anything.
  • A call made through a base-class reference reaches the derived version only when the override succeeds. A misspelled derived function is a separate function that base-class calls never reach.
  • The override keyword asks the compiler to confirm that a declaration really overrides a base virtual function, and it reports an error when the confirmation fails, turning a silent bug into an immediate one.
  • Overriding mistakes share one root cause: a declaration that does not line up with anything in the base class. The fix is to correct the declaration so that its name, parameters, and qualifiers match the base function.

Related concepts

More concepts starting with U