Function Overloading in C++

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.

You can only overload functions only on the basis of:

  • Type of arguments
  • Number of arguments
  • Sequence of arguments &
  • Qualifiers like const and volatile.
Consider the following function:
        int Add(int x, int y)
       {
                return x+ y;
       }
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.Again we have to write one more function with float variables.
One way to work around this issue is to define multiple functions with slightly different names:
      int AddI(int x, int y)
     {
              return x+ y;
     }
     double AddD(double x, double y)
     {
             return x+ y;
     }

Function overloading provides a better solution
We now have two version of Add():
      int Add(int nX, int nY); // integer version
      double Add(double dX, double dY); // floating point version

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). In fact, we can define as many overloaded Add() functions as we want, so long as each Add() function has unique parameters.

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:
          void Print(char *szValue);
          void Print(int nValue);

          Print(0); // exact match with Print(int)


Although 0 could technically match Print(char*), it exactly matches Print(int). Thus Print(int) is the best match available.

2) If no exact match is found, C++ tries to find a match through promotion.

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:

         void Print(char *szValue);
         void Print(int nValue);
        
         Print('a'); // promoted to match Print(int)

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 found, C++ tries to find a match through standard conversion. 


Standard conversions include:

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

For example:
         void Print(float fValue);
         void Print(struct sValue);

         Print('a'); // promoted to match Print(float)


In this case, because there is no Print(char), and no Print(int), 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.

Ambiguous matches:

class A


        public: 
               void foo(int x) 
               {
                  cout << "foo with one\n"; 
               } 
               void foo(int x, int y=10) 
               { 
                  cout << "foo with two\n";
               } 

}; 
int main() 


      A a; 
      a.foo(1); //error? 
}

Because function/operator overloading is resolved by compiler at compile time. So overloading a function just by providing a default argument will cause ambiguity and compiler error.

No comments:

Post a Comment