Search

8.9 — Introduction to function overloading

Consider the following function:

This trivial function adds two integers and returns an integer result. However, what if we also want a function that can add two floating point numbers? This add() function is not suitable, as any floating point parameters would be converted to integers, causing the floating point arguments to lose their fractional values.

One way to work around this issue is to define multiple functions with slightly different names:

However, for best effect, this requires that you define a consistent function naming standard for similar functions that have parameters of different types, remember the names of these functions, and actually call the correct one.

And then what happens when we want to have a similar function that adds 3 integers instead of 2? Managing unique names for each function quickly becomes burdensome.

Introduction to function overloading

Fortunately, C++ has an elegant solution to handle such cases. Function overloading allows us to create multiple functions with the same name, so long as each identically named function has different parameters (or the functions can be otherwise differentiated). Each function sharing a name (in the same scope) is called an overloaded function (sometimes called an overload for short).

To overload our add() function, we can simply declare another add() function that takes double parameters:

We now have two versions of add() in the same scope:

The above program will compile. Although you might expect these functions to result in a naming conflict, that is not the case here. Because the parameter types of these functions differ, the compiler is able to differentiate these functions, and will treat them as separate functions that just happen to share a name.

Key insight

Functions can be overloaded so long as each overloaded function can be differentiated by the compiler. If an overloaded function can not be differentiated, a compile error will result.

Related content

Because operators in C++ are just functions, operators can also be overloaded. We’ll discuss this in 13.1 -- Introduction to operator overloading.

Introduction to overload resolution

Additionally, when a function call is made to function that has been overloaded, the compiler will try to match the function call to the appropriate overload based on the arguments used in the function call. This is called overload resolution.

Here’s a simple example demonstrating this:

The above program compiles and produces the result:

3
4.6

When we provide integer arguments in the call to add(1, 2), the compiler will determine that we’re trying to call add(int, int). And when we provide floating point arguments in the call to add(1.2, 3.4), the compiler will determine that we’re trying to call add(double, double).

Making it compile

In order for program using overloaded functions to compile, two things have to be true:

  1. Each overloaded function has to be differentiated from the others. We discuss how functions can be differentiated in lesson 8.10 -- Function overload differentiation.
  2. Each call to an overloaded function has to resolve to an overloaded function. We discuss how the compiler matches function calls to overloaded functions in lesson 8.11 -- Function overload resolution and ambiguous matches.

If an overloaded function is not differentiated, or if a function call to an overloaded function can not be resolved to an overloaded function, then a compile error will result.

In the next lesson, we’ll explore how overloaded functions can be differentiated from each other. Then, in the following lesson, we’ll explore how the compiler resolves function calls to overloaded functions.

Conclusion

Function overloading provides a great way to reduce the complexity of your program by reducing the number of function names you need to remember. It can and should be used liberally.

Best practice

Use function overloading to make your program simpler.


8.10 -- Function overload differentiation
Index
8.8 -- Type deduction for functions

148 comments to 8.9 — Introduction to function overloading

  • Inevitable

    one of the rare cases that Best practice doesn't forbid us from using something and gives us liberty :)

  • Waldo Lemmer

    I love this new chapter, but I think you should introduce function signatures in this lesson, or at least in this chapter.

    Edit: The next lesson is a great candidate for this.

  • knight

    I am sorry, I do not understand this purpose. Is it meaning do not use same variable in different function?

    • Knight

      Am I right: because

      will reture different value, so the

      get the wrong value frome the

    • nascardriver

      There's no error in this code, it's working. The example is only trying to show that out-parameters make the code ugly.
      Rather than writing

      we have to write the 3 lines you quoted.

  • James C

    Best practice labelled as rule.

  • Hassan

    Are function returns always not considered? or does making the return constant in one variant is an exception?

    For example:

    Is this a valid function overloading?

    • Alex

      Return types are not considered at all, regardless of type.

      • Hassan

        Is what we have in lesson 11.12 "Const class objects and member functions" a different thing?
        I mean getValue() function in this snippet about "Overloading const and non-const function":

        • Alex

          Yes, the const qualifier on member functions is considered during overload resolution. The fact that they have different return types is irrelevant/circumstantial.

  • EternalSkid

    Hi Alex and nascardriver, i had a confusion over this statement, are you able to explain it to me?

    print(0) is similar. 0 is an int, and there is no print(int). It matches both calls via standard conversion.

    However, can't 0 be promoted to an unsigned integer through numeric promotion? Thanks for your time, highly appreciate it!

    • Alex

      int will not be promoted to unsigned int. That is considered a conversion, so the compiler is unable to determine whether print(unsigned int) or print(float) is a better match.

  • Mahmoud

    Hi,
    In the section "Typedefs are not distinct", how does the compiler differentiate between the type string that in the header <string> and the alias  "string" that refers to char* ????

    • Alex

      The string in the string header is part of the std:: namespace, whereas the string that refers to char* isn't.

      In general, string will refer to the char* typedef, and std::string will refer to std::string. There's one exception to this (code in a namespace will "prefer" the type defined in the namespace to the global type) but it shouldn't matter (because you should never be defining code inside namespace named "std")

    • Mahmoud

      I Got it, Thanks for This Big Effort.

  • kio

    Hi Alex and Nascardiver, so using the keyword "auto" is a good candidate here?
    Because the compiler will not look at the return type of the function, right? It only scans for the function parameters.

    • nascardriver

      Hi kio!

      `auto` return types should be avoided. Anyone who wants to use your function has to read its definition to know what the return type is. There are cases where `auto` return types can reasonably be used, but they're rare.

      If you want to have an `add()` function for all types, templates are a better candidate than `auto`.

      • kio

        Hi Nascardriver, you are right about the "auto" keyword. I was looking about templates last night, I'm looking forward to reaching the chapter where we are going to tackle it!
        Thanks for your time and response.

  • SuperNoob

    > "2) If no exact match is found, C++ tries to find a match through promotion. In lesson a previous lesson, we covered how certain types can be automatically promoted via internal type conversion to other types. To summarize,"

    ---> The second line, should be "In a previous lesson,"

  • Andreas Krug

    Three small suggestions:

    ..., the following two declarations of print() are considered identical:
    instead of
    ..., the following two declarations of Print() are considered identical:

    In lesson 6.15 — Implicit type conversion (coercion), ...
    instead of
    In lesson 4.4 -- type conversion and casting, ...

    ..., the function call print(value) will resolve to the print(int) version of the function.
    instead of
    ..., the function call print(value) will resolve to the Print(int) version of the function.

  • J34NP3T3R

    but even if its a double, it sure seems like its closer to a float than an unsigned integer. can it not do a standard conversion from double to float and match print(float) ?

  • To steal a phrase from Andreas Krug, shouldn't the note for advanced readers be in a beautiful gray box?

  • huroa

    Just a suggestion: you could replace the typedef with a more modern "using type alias". The syntax to understand to whom the asterisk actually belongs to is quite hard to remember correctly when dealing with typedefs and pointers

  • Galih

    How about overloading like this?

    Is this allowed?

    I guess if it is allowed,

    is equal with

    ?

    • nascardriver

      It is not allowed. `const` is removed from value parameters during function lookup, so your 2 `myfunction` are the same.

      • Galih

        It looks like i made a mistake, rather than

        it was supposed to be something like this

  • jenga

    >> We now have two version of add():

    looks like you missed an s at the end of "version" there
    also the rule at the end should be put in it's proper home, the beautiful green box

  • Tony

    >In this case, because there is no print(char), the char ‘a’ is promoted to an integer, which then matches print(int).

    Isn't print(char *value) taken here, since we're passing a char?

  • sami

    Hi,
    I was wondering why I get the following compile error:
    2 overloads have similar conversions
        

    • nascardriver

      For each possible function, there'd have to be 1 conversion. Either from int to double or from double to int. No overload is a better match than the other. Use double literals when you use doubles.

      • Yousuf

        So compiler is confused which version of the function is to choose because both versions require only one conversion of the arguement to fit?

        • nascardriver

          Indeed. If neither function is a better match than the other, the compiler is helpless. You can explicitly tell the compiler which overload to call by performing a cast on the function pointer, but that's only a last resort if the clash is in a library and you're unable to update your functions. If such a clash occurs in your code, update the functions to resolve it (eg. by renaming one).

  • marius

    It looks awful for me. Implicit conversions is what I hate the most in programming by now. C++ is strongly typed. This is good. Let it be that way.
    Implicit conversion is possible unwanted magic behind the scene. You call a function and the compiler chooses the best match, possibly not the one you think (different behavior) at the call moment ...
    Better use templates. At least there you tell the compiler you want the same behavior for all types. Aka the function you think at call moment.

  • satamakotka

    Should this

    be

    or am I just not understanding it?  If you make char and a pointer to a string equal using a typedef, does that also make a pointer to a char and a regular string equal too?

    • nascardriver

      It's correct as written. They placement of the asterisk might confuse you

  • Sandeep Dhakal

    How is it decided as to whether promote or convert a data type to another?
    For eg, char value is 'promoted' to int, but it is 'converted' to unsigned int. I am having a difficult time remembering all these data types either being promoted or converted to another form. Can you please help?
    I am particularly confused due to the following lines.

    void print(unsigned int value);
    void print(float value);

    print('a');
    print(0);
    print(3.14159);
    In the case of print('a'), C++ can not find an exact match. It tries promoting ‘a’ to an int, but there is no print(int) either. Using a standard conversion, it can convert ‘a’ to both an unsigned int and a floating point value.

  • Napalm

    1. I wanted to check that you still need separate function declarations when the parameters are different but return type is the same.

    2. For small functions, is this the right way to organise files? With separate .h and .cpp? Or would you put the definitions in the .h file?

    Functions.h

    Functions.cpp

  • Nirbhay

    Hi!

    Typedefs are not distinct

    Since declaring a typedef does not introduce a new type, the following two declarations of Print() are considered identical:

    typedef char *string;
    void print(string value);
    void print(char *value);

    I do not understand the use of '*' here. Please explain.

    Thanks :)

  • hassan magaji

    thanks alot nas...

  • hassan magaji

    hi Alex,
    i've seen some using function-like macros and deprecating function overloading
    like this:

    is this advisable anyway?

    ...ready to stick to your rules/recommendations always...

Leave a Comment

Put all code inside code tags: [code]your code here[/code]