10.7 — Function overloading

Function overloading is a feature of C++ that allows us to create multiple functions with the same name, so long as they have different parameters. Consider the following function:

This trivial function adds two integers. However, what if we also need to add two floating point numbers? This function is not at all 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 naming standard, remember the name of all the different flavors of the function, and call the correct one.

Function overloading provides a better solution. Using function overloading, we can simply declare another add() function that takes double parameters:

We now have two versions of add():

Although you might expect this to cause a naming conflict, that is not the case here. The compiler is able to determine which version of add() to call based on the arguments used in the function call. If we provide two ints, C++ will know we mean to call add(int, int). If we provide two floating point numbers, C++ will know we mean to call add(double, double). In fact, we can define as many overloaded add() functions as we want, so long as each add() function has unique parameters.

Consequently, it’s also possible to define add() functions with a differing number of parameters:

Even though this add() function has 3 parameters instead of 2, because the parameters are different than any other version of add(), this is valid.

Function return types are not considered for uniqueness

A function’s return type is NOT considered when overloading functions. (Note for advanced readers: This was an intentional choice, as it ensures the behavior of a function call or subexpression can be determined independently from the rest of the expression, making understanding complex expressions much simpler. Put another way, we can always determine which version of a function will be called based solely on the arguments. If return values were included, then we wouldn’t have an easy syntactic way to tell which version of a function was being called -- we’d also have to understand how the return value was being used, which requires a lot more analysis).

Consider the case where you want to write a function that returns a random number, but you need a version that will return an int, and another version that will return a double. You might be tempted to do this:

The compiler will flag this as an error. These two functions have the same parameters (none), and consequently, the second getRandomValue() will be treated as an erroneous redeclaration of the first.

The best way to address this is to give the functions different names:

An alternative method is to make the functions return void, and have the return value passed back to the caller as an out parameter (see lesson 10.3 -- Passing arguments by reference if you need a reminder what an out parameter is).

Because these functions have different parameters, they are considered unique. However, there are downsides to doing this. First, the syntax is awkward, and you can’t route the output of this function directly into the input of another. Consider:

Also, the type of the argument passed in must match the type of the parameter exactly. For these reasons, we don’t recommend this method.

Typedefs are not distinct

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

How function calls are matched with overloaded functions

Making a call to an overloaded function results in one of three possible outcomes:

1) A match is found. The call is resolved to a particular overloaded function.
2) No match is found. The arguments can not be matched to any overloaded function.
3) An ambiguous match is found. The arguments matched more than one overloaded function.

When an overloaded function is called, C++ goes through the following process to determine which version of the function will be called:

1) First, C++ tries to find an exact match. This is the case where the actual argument exactly matches the parameter type of one of the overloaded functions. For example:

Although 0 could technically match print(char*) (as a null pointer), it exactly matches print(int) (matching char* would require an implicit conversion). Thus print(int) is the best match available.

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,

  • Char, unsigned char, and short is promoted to an int.
  • Unsigned short can be promoted to int or unsigned int, depending on the size of an int
  • Float is promoted to double
  • Enum is promoted to int

For example:

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

3) If no promotion is possible, C++ tries to find a match through standard conversion. Standard conversions include:

  • Any numeric type will match any other numeric type, including unsigned (e.g. int to float)
  • Enum will match the formal type of a numeric type (e.g. enum to float)
  • Zero will match a pointer type and numeric type (e.g. 0 to char*, or 0 to float)
  • A pointer will match a void pointer

For example:

In this case, because there is no print(char) (exact match), and no print(int) (promotion match), the ‘a’ is converted to a float and matched with print(float).

Note that all standard conversions are considered equal. No standard conversion is considered better than any of the others.

4) Finally, C++ tries to find a match through user-defined conversion. Although we have not covered classes yet, classes (which are similar to structs) can define conversions to other types that can be implicitly applied to objects of that class. For example, we might define a class X and a user-defined conversion to int.

Although value is of type class X, because this particular class has a user-defined conversion to int, the function call print(value) will resolve to the print(int) version of the function.

We will cover the details on how to do user-defined conversions of classes when we cover classes.

Ambiguous matches

If every overloaded function has to have unique parameters, how is it possible that a call could result in more than one match? Because all standard conversions are considered equal, and all user-defined conversions are considered equal, if a function call matches multiple candidates via standard conversion or user-defined conversion, an ambiguous match will result. For example:

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. Because all standard conversions are considered equal, this is an ambiguous match.

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

print(3.14159) might be a little surprising, as most programmers would assume it matches print(float). But remember that all literal floating point values are doubles unless they have the ‘f’ suffix. 3.14159 is a double, and there is no print(double). Consequently, it matches both calls via standard conversion.

Ambiguous matches are considered a compile-time error. Consequently, an ambiguous match needs to be disambiguated before your program will compile. There are a few ways to resolve ambiguous matches:

1) Often, the best way is simply to define a new overloaded function that takes parameters of exactly the type you are trying to call the function with. Then C++ will be able to find an exact match for the function call.

2) Alternatively, explicitly cast the ambiguous argument(s) to the type of the function you want to call. For example, to have print(0) call the print(unsigned int), you would do this:

3) If your argument is a literal, you can use the literal suffix to ensure your literal is interpreted as the correct type:

The list of the most used suffixes can be found in lesson 4.13 -- Literals.

Matching for functions with multiple arguments

If there are multiple arguments, C++ applies the matching rules to each argument in turn. The function chosen is the one for which each argument matches at least as well as all the other functions, with at least one argument matching better than all the other functions. In other words, the function chosen must provide a better match than all the other candidate functions for at least one parameter, and no worse for all of the other parameters.

In the case that such a function is found, it is clearly and unambiguously the best choice. If no such function can be found, the call will be considered ambiguous (or a non-match).

For example:

In the above program, all functions match the first argument exactly. However, the top function matches the second parameter exactly, whereas the other functions require a conversion. Therefore, the top function (the one that prints ‘a’) is unambiguously the best match.


Function overloading can lower a program’s complexity significantly while introducing very little additional risk. Although this particular lesson is long and may seem somewhat complex (particularly the matching rules), in reality function overloading typically works transparently and without any issues. The compiler will flag all ambiguous cases, and they can generally be easily resolved.


Use function overloading to make your program simpler.

10.8 -- Default arguments
10.6 -- Inline functions

128 comments to 10.7 — Function overloading

  • Deepesh

    Hey Alex!

    What if I have two functions with same name, but 2 and 3 parameters with the third parameter having a default value, like this:

    When I write foo(2, 4) which function is called? Is it legal, or is it another ambiguous situation?
    If legal, then how do I write different statements to call the two functions?

  • Shouldn't "matching char* would require an implicit conversion"  be "explicit conversion" ?

    • Alex

      No, 0 will match char* implicitly, since 0 can represent a null pointer in this context, and the compiler will be happy to do the conversion for you.

      • ah thanks, i understood it back words as if we want the (char*) be the function to be called so while there is an exact match so i thought we need a conversion to call that version of the function!

  • jp

    hello, I have to next code:

    #include <iostream>
    using std::cout;

    void f(float) { cout << "f(float)"; }
    void f(long double) {cout << "f(long double)"; }

    int main() {
    has one error, but if I change long double for double already work like this:

    #include <iostream>
    using std::cout;

    void f(float) { cout << "f(float)"; }
    void f(double) {cout << "f(long double)"; }

    int main() {
    and other question,there is one compilation error or linker error?.
    how identificate compilation error or linker error?

    • Hi jp!

      The first version doesn't work, because 2.0 is a double, none of the versions of @f takes a double, but both versions could take a double by implicitly casting 2.0 to either a float or a long double. You can pass 2.0f or 2.0l to call one or the other function.
      @main is missing a return statement.
      It's a compilation error.

      > how identificate compilation error or linker error?
      Depends on your compiler. A linker error will usually have link, linker, ld or similar near the message.

  • Ramesh

    I am not able to understand this section-> Matching for functions with multiple arguments
    Could you give some example programs?

  • Peter Baum

    Regarding: "Note that the function’s return type is NOT considered when overloading functions."

    Here is an example of what looks like an arbitrary rule, and therefore yet another arbitrary rule for the student to memorize.  Perhaps it would be better to explain that the compiler would have a hard time choosing the required function from the return type (at least in many instances).  With such an explanation, it isn't just an arbitrary rule, but something that actually makes sense.

    • Alex

      Good point. I added a little context about why this choice was intentionally made, for readers who care. Is the explanation clear or confusing?

      • Peter Baum

        Regarding: "(Note for advanced readers: This was an intentional choice, as it ensures the behavior of a function call or subexpression can be determined independently from the rest of the expression, making understanding complex expressions much simpler)."

        Here is an alternative: The reason for this choice is that the return type of a function call is not a syntactic element when the function is called.  As an example of the problem, suppose we create two similar functions with no parameters.  One function returns int and the other long. One of those functions might be used in an expression that converts the integer value to double, and there is no general syntactic element to indicate which function is being requested.

  • Trevor

    If you want to create two functions with the same name and same parameters (if any) but which return different types, then you can create functions with a void return type and pass the address that the return value is to be stored in as a parameter. This new parameter will be a pointer to the required type and therefore able to disambiguate the two functions, e.g.
    void createRandomFraction( double *result );
    void createRandomFraction( float *result );


  • Trevor

    For resolving ambiguous matches using option 2, as well as type casting, if one or more arguments are literals, then suffixing the literals to match one of the function’s parameters would also work (and I would say be more readable). For example, instead of

    just use

    The table in section 2.8 is quite useful for this.


  • Michael

    Hi Alex,
    In 1.7 you said "However, there is a small subset of declarations that are not definitions, such as function prototypes. These are called pure declarations. Others types of pure declarations include forward declarations for variables, class declarations, and type declarations (you will encounter these in future lessons, but don’t need to worry about them now). You can have as many pure declarations for an identifier as you desire (although having more than one is typically redundant)."

    then why having

    would cause the compiler to throw an error?


    • Alex

      Because you can't have a function prototype that only differs by return value. If you were to call getRandomValue(), the compiler wouldn't be able to disambiguate which one you wanted to call.

      You can have:

      It's redundant, but syntactically legal.

  • Evan

    Isn't it much more efficient for the program to have unique function names than having to go through all of the overloaded functions to find the right match?

    • Alex

      It's more efficient for the compiler (the compiler is the one resolving all the function calls) -- but this isn't what you should be optimizing for. You should be optimizing for ease of use and maintainability.

      • So, that means we should maintain readability of the program by avoiding function overloading?

        • Alex

          No, rather the opposite. You should use function overloading whenever it makes sense. If you have two functions that add numbers, one which works on integers and the other on floats, it's much better to name them both add than name one addint and the other addfloat.

  • Nurlan

    Hello, Alex

    1) I hope, you are doing well. Thanks for the great tutorial!
    -Below program is  Standard conversion or Numeric conversion ? add(2.99,8.91)-> float add(float x, float y);
    2.99 and 8.91 are doubles converted to float.

    float add(float x, float y)
        return x + y;
    int main()
          std::cout<<add(2.99,8.91)<<'n';//Standard conversion or Numeric conversion?                                                                  
          return 0;                      

    2)  In in this "4.4-implicit-type-conversion-coercion" topic you have quoted as  below:
    Numeric conversions

    When we convert a value from a larger type to a similar smaller type, or between different types, this is called a numeric conversion. For example:
    double d = 3; // convert integer 3 to a double
    short s = 2; // convert integer 2 to a short

    int i = 10;
    float f = i;


    Standard conversions include:
        Any numeric type will match any other numeric type, including unsigned (eg. int to float)  

    -But,you haven't talked about Numeric conversion in function overloading.Is there any use of Numeric conversion?If there is a use, please could you briefly tell us how to differentiate between numeric and standard conversions.

    Thanks in Advance!

    • Alex

      In this case, you're providing arguments that are double literals, but the function is expecting float parameters. Therefore, it will do a floating point numeric narrowing conversion.

      A numeric conversion is a type of standard conversion.

  • Prajwal

    "Which version of add() gets called depends on the arguments used in the call -- if we provide two ints, C++ will know we mean to call add(int, int). If we provide two floating point numbers, C++ will know we mean to call add(double, double) "
    Could you write down an example program for this statement,asking the user to input a value ,based on the user's input (whether the user passed an int value or double vale) and calling the right function ? I tried working around with this,but could not exactly figure it out.As in function overloading several functions have the same name but just differ in data types used in params ,however they might have same variable,if that's the case how to figure out to call the right function ?

    • Alex

      There's no easy way to ask the user for an input and vary the data type based on what the user entered. Here's a program showing function add called with different parameter types

      There's no way to pass the same value or variable and have it determine which function to call on the fly -- which function to call is determined at compile time based on the types involved.

  • Paul

    Extremely small typo: "Function overloading can lower a programs complexity " should be program's.

    I love this guide and have been learning a lot in the past week. Thank you for sharing this!

  • Matt

    Under "Typedefs are not distinct", you wrote:

    "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 was a little confused about this. I don't remember much about what you wrote regarding typedef in an earlier section, and I had trouble finding it. How are you able to define "string" as a synonym for "char *"? I would think that the "string" name would invalid since it's already taken. Is it not considered a reserved identifier? Is this typedef example only possible when the string needs to be qualified with it's full name(std::string)?

    Also, if "string" is stolen as a synonym for "char *", does this mean that we can no longer define variables of type string(actual)?

    • Alex

      typedef char *string; defines "string" as a synonym for char*. I cover typedefs in lesson 4.6.

      string is only a taken name in the context of namespace std. string is not a keyword or reserved word.

      You will run into problems here if you do "using namespace std" because then std::string will conflict with this string. But I highly do not recommend using namespace std!

  • Nyap

    I think that the typedef section is confusing because it's pretty obvious already

    so this will still work, right?

    • Nyap

      also, why does posting a comment take so long? sometimes I even get an error and when I go back to this page the comment is there but I can't edit or delete it

      My internet is pretty decent

      • Nyap

        I just got one of those errors and can't edit the comment

      • Alex

        I'm not really sure. Some days the comments go through quickly, other days they take a while, and occasionally they error out. I haven't been able to figure out why. It's an issue on my end, not yours.

    • Alex

      Yup, if lol is an int and blob is a float, then the functions will be considered distinct.

  • J3ANP3T3R

    Ohhh sounds risky and confusing to debug. i hope i never have to use function overloading.

    • Alex

      Really, the most important thing here is just understanding that function overloading exists and how to us it. All of the conversion stuff only comes into play if you provide arguments of the wrong type for the function, which you probably shouldn't be doing anyway. :)

      If you understand the add() example at the top of the lesson, that's good enough to move on.

  • Scoobadood

    Thanks for the resource Alex. It's been years since I wrote C++ and I'm finding this a great way to get up to speed with changes in the languages.

    A question. Given the following:

    If (lazily) I invoke [pre]Foo[/pre] as follows:

    Where the intention is to invoke the (float, float ,float) constructor, I actually get the (int, int, float) constructor. I understand that this is because, all other things being equal, converting int to float 3 times is a worse match than converting one int to float.

    Can I use the 'explicit' keyword to prevent this conversion or is this a misuse/inappropriate approach? E.g. is this reasonable:

    • Alex

      Yes, you can use the explicit keyword to prevent C++ from use a given constructor as a conversion constructor. That's precisely what it's meant for.

  • Shiva

    > X value; // declare a variable named cValue (value) of type class X

    Strange wording:
    > If no promotion is found, C++ tries to find a match... (If no match is found by promotion could be a better standard :) )

    Finally we're into OOP, right? Why isn't this exciting news mentioned anywhere, Alex? :D

    • Alex

      Lesson updated. Not quite into OOP yet -- we get there in chapter 8, and all of these things come in handy. :)

      • Shiva

        Of course, I can't wait to get into Chapter 8! Well function overloading is one type of OOP's polymorphism, so we already get a peek in, right?

        And I got the email notification about your reply. Thanks for implementing that. :)

  • Rob G.

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

    Being nitpicky remove the 'the' between "following the two declarations". Should read : 'the following two declarations of Print()...

    Hope this is helpful.

  • Kevin

    If you could add tiny quizzes at the end of each lesson, that would greatly help with memory retention in my opinion. I'm not talking writing code, but I mean something like... asking the reader to get some paper and write the terms defined within that particular lesson from memory to see if they fully understand it. Yeah, people will cheat... but this is all self taught anyways. The only person losing in that case is them.

    I can understand if you don't have time, but with tiny quizzes like this you could pretty much pass it off to anyone, since the only effort involved is writing a few sentences at the end of each, asking the reader what ambiguous matches are, or asking what an enum will be promoted to (for example).

  • I encountered a really strange thing! ~ Look at the following code:

    When compiling this program compiler give me an error:
    error: call of overloaded 'add(double, double)' is ambiguous
    and when I changed 'float' to 'double' everything went OK!
    Except both 'float' and 'double' aren't floating point number?
    so why we have an compiler error here?

  • developer

    i was expecting name mangling here

    • Alex

      Name mangling is an interesting topic, but it's really an internal compiler detail, and one that doesn't need to be understood to use C++ effectively.

  • Jyoti

    Hi Alex..
    I have heard that "Avoid overloading function where one takes integral type argument and other takes pointer"
    What could be the reason?


    • Alex

      I presume the reason is because the literal 0 could match as an integer or a null pointer value. In practice, I can't ever recall seeing this cause a real problem -- at most, it would trigger an ambiguous match that could be resolved via an explicit cast.

  • Matt

    This really confuses me here.

    typedef char *string;
    void Print(string szValue);
    void Print(char *szValue);

    What exactly does the asterisk do in this situation? The closest thing I can relate it to is the pointer stuff but it's not pointing to any address here. I tried reviewing the previous lessons again but I still don't get it.

  • Above it says:

    There are two ways to resolve ambiguous matches:

    1) Define a new overloaded function that takes parameters of exactly the type you are trying to call the function with.

    2) Explicitly cast the ambiguous parameter(s) to the type of the function you want to call.

    I would propose a third way:

    3) Simply give each and every function a unique name.

    In other words, avoid problems with overloading by not using overloading. At least as long as you don't see considerate advantages with using overloading.

    PS: Though I'm rather good at PHP, that reminds of C++, I'm a C++ beginner and have never used overloading. Please correct me if you have more experience of C++ than I have and disagree with the piece of advice above.

    • smitha

      Not that am an expert in C++ but overloading is one of the key concepts of C++ through which it implements polymorphism. The advantage is in terms of usability of a function .

      The classic textbook example would be a call a function Area() to find the area of different shapes depending on the number of parameters.
      Overloading would basically be used when you need to do the same thing in different ways. for example finding the area of a rectangle is different from finding the area of a circle.
      Area(int l, int b);
      Area(int r);

      So here the decision as to which function should be executed goes automatically to the compiler and not to the programmer and thereby reducing the number of if-else statements.

    • Vivek

      Overloading is very useful, especially for class constructors.

    • Eiq

      As smitha said, consider several classes that are derived from some base class (triangle, circle and square from object). Now you put thousands of them into vector and want to find their combined area. So you would probably run through some for cycle.
      With overloading you just call area() member function for each one of them. Without overloading you would have to find out what class is the current class and then call appropriate function.

    • Alex

      Giving related functions a different name is almost never going to be the best option. The benefits from consistency outweigh the few problems that overloading might cause.

      As other posters have also noted, there are many cases where overloading is the only option (cases in which you can't just rename the function). Two of the most common are overloaded operators (defining your own operator+, for example) and class constructors, which must take the name of the class. We'll cover those in the next few chapters. This one just introduces the general concept.

  • smitha

    "If there are multiple arguments, C++ applies the matching rules to each argument in turn. "

    if this is true, then why does the compiler report an ambigous call for the following code:

    • Alex

      This case is ambiguous because neither function is better than the other: each function has one matching parameter and one parameter that will only match via a standard conversion.

  • smitha

    Can functions be overloaded on the basis of one of the arguments being a pointer?

    The compiler doesnt throw an error , so I presume that it is valid, but what I dont understand is that essentially both the arguments are of type int.(even if one contains an address). Kindly explain

    • Alex

      Yes, you can have overloaded functions where one takes an int and the other a pointer to an int. An int and a pointer to an int are distinct types, and thus the compiler can resolve which function to call.

  • TomarBueno

    This is a excellent side to get answer clear neat.......

  • Tom

    Hello Alex -

    Another small typo:

    "Consequently, an ambiguous match needs to be disambiguated before your program will compiler."

    Also, it would help if there were more quiz questions and exercises to reinforce the material - there is a lot here to remember.


    • Thanks for the note. As you've noticed, the number of quiz questions and exercises falls off significantly as you go through the tutorials. The reason for this is simple: they take a long time to write, especially as we get into more complex subjects.

      Given a limited amount of time to work on this site, I decided there was more benefit to spending my time writing subject tutorials than quiz questions. Once the tutorials are done (which actually isn't that far off now), I do intend to go back and add more quiz questions and exercises.

      • cpplx

        i was just thinking how my learnig degraded since im a "learn by doing" type.

        • Alex

          Because there aren't as many quiz questions in the later lessons? I'm working to fix that but I haven't gotten this far yet. :(

          • cpplx

            i lack any practice. i will soon forget how to write a helloworld.
            i understand it does not happen in a snap and just letting you know how usefull(or not) your site is(the further i read. im at 7.13 atm).

          • Pablo

            I agree with Tom and ccplx, but it is great knowing you have this in mind! I will stay alert for future updates.

            Good work!

            PS: I also agree this material would make a successful book, specially given that the website is quite well known by now!

  • Aaron

    "In this case, because there is no Print(char), the char 'a' is promoted to an integer, which then matches Print(int)."

    There is a Print(char) though!!

    • No there isn't. :) There's a Print(int) and a Print(char*). Print(char*) is not the same thing as Print(char). Print(char) would be used for single character. Print(char*) would be used to print C-style character strings.

  • this is very good site for c++.

Leave a Comment

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