HOWTO · C++

Function Overloading VS Overriding in C++

This article explores the differences between function overloading and overriding in C++. It provides clear examples and explanations to help C++ programmers understand how to use these powerful features effectively. Discover how to enhance your code's flexibility and maintainability with these essential concepts.

On this page

Function overloading and function overriding solve different problems in C++. Function overloading gives functions in the same scope the same name with different parameter lists; the compiler selects a match from the call’s arguments. Function overriding lets a derived class replace an inherited virtual function with a matching implementation; a call through a base reference or pointer is dispatched to the derived object at runtime.

What overloading and overriding mean in C++

Overloading is about choosing among functions that differ by their parameters. Overriding is about substituting behavior in an inheritance hierarchy. A function’s return type alone does not distinguish an overload, and overriding requires a virtual function in the base class. The override specifier makes the compiler check that a derived declaration really matches a base virtual function.

How function overloading works

Declare functions with the same name in one scope and give them distinct parameter lists. The list can differ in the number or types of parameters. At a call, overload resolution uses the arguments and the candidates’ parameter types. Return type is not used to select an overload, so two declarations that differ only by return type are not a valid overload set.

Run this example:

#include <iostream>

class Formatter {
public:
    void show(int value) const {
        std::cout << "integer: " << value << '\n';
    }

    void show(double value) const {
        std::cout << "decimal: " << value << '\n';
    }
};

int main() {
    Formatter formatter;
    formatter.show(7);
    formatter.show(2.5);
}
integer: 7
decimal: 2.5

Supplied runtime evidence confirms that this example executed successfully with that output. The integer and decimal arguments select different show overloads. When adding an overload, make sure its parameter list differs meaningfully and that calls remain unambiguous.

How function overriding works

A base class declares a function virtual; a derived class provides a function with a matching name, parameter list, and compatible qualifiers and return type. Mark the derived declaration override so a mismatch becomes a compile-time diagnostic. Virtual dispatch chooses the final overrider for the object when the function is called through a base reference or pointer.

Run this example:

#include <iostream>

class Message {
public:
    virtual void print() const {
        std::cout << "message\n";
    }
};

class Alert : public Message {
public:
    void print() const override {
        std::cout << "alert\n";
    }
};

int main() {
    Alert alert;
    const Message& message = alert;
    message.print();
}
alert

Supplied runtime evidence confirms that this example executed successfully with that output. Although message has the base type, it refers to an Alert, so the virtual call uses Alert::print. A base class may also declare a pure virtual function with = 0; such a class is abstract and cannot be instantiated until concrete derived classes implement its pure virtual functions.

Overloading vs overriding: key differences

Aspect Function overloading Function overriding
Purpose Provide same-name operations for different arguments Specialize inherited behavior for a derived type
Requirement Distinct parameter lists in the same scope Inheritance and a matching base virtual function
Selection Compile-time overload resolution from the call arguments Runtime virtual dispatch through a base reference or pointer
Useful check Ensure calls identify the intended overload Add override to verify the declaration matches

Overloads can exist without inheritance or virtual functions. Overrides depend on inheritance and virtual dispatch; they are not selected by passing a different argument list.

Common mistakes and how to recognize them

A derived function with the same name does not automatically override a base function. If the base function is not virtual, the derived declaration hides the base name rather than enabling virtual dispatch. If a parameter, const qualifier, or other part of the function type does not match, the intended override may fail; writing override exposes that mismatch at compile time.

Do not attempt to overload solely by changing a return type. Also avoid passing derived objects by value when you expect polymorphic behavior: copying one into a base object slices away the derived portion. Use a base reference or pointer to preserve dynamic dispatch. For ordinary ownership, prefer automatic objects or smart pointers; if deleting a derived object through a base pointer, the base class should have a virtual destructor.