Lecture 5: Function Overloading



Lecture 5: Function Overloading


A C++ compiler is smarter than a C compiler in the way it differentiates functions. Instead of just looking at the name, it looks at something called the "signature" of a function which is the name of the function, the number and types of arguments and whether the function is const. This signature is almost the same as the prototype, except it doesn't include the return type.
The compiler will actually go to a significant amount of effort to find a function to fulfill a function call specified by the programmer. Given its list of functions with the same name, it goes through the following sequence of steps according to the specification outlined in the 2nd edition of Stroustrup's book:
  1. Find a function that matches exactly, or with trivial conversions.
  2. Do promotions on the arguments to find a match. A promotion moves an integer into a smaller or larger integer, or a floating-point number into a smaller or larger floating-point number. "promotions" to smaller types seem risky due to truncation problems, so perhaps here a compiler warning is to be expected. g++ didn't have any problem with promoting an int to a char.
  3. Do standard conversions. A conversion changes the representation of a number from floating-point to integer or vice versa. Also included in standard conversions are those implied by polymorphism.
  4. Do program-defined conversions. Only one level of conversion is allowed here. Program-defined conversions are single-argument constructors and conversion member functions.
  5. Look for an ellipsis version of the function.
This sequence is actually obsolete for most compilers. ANSI has drafted the definitive one. It does give the approximate flavor of what is involved in overloading resolution.
At each level, the compiler looks for a match. If it finds one function that works, then that's the one that's used and the search is over. If it can't find at least one, then it goes on to the next level. If it finds more than one, it flags an ambiguity error. The rules are chosen so that, when the choice is obvious, the compiler can choose the correct version of the function to call without the programmer having to supply all the details of what needs to be converted to what, and yet. when the programmer makes a mistake and codes a call where the correct function to use isn't obvious, the compiler can spot this and flag an ambiguity.
Ambiguity errors merely signify that the compiler needs more information about the programmer's preferences to resolve the call. The programmer can do this by explicitly doing the argument conversions necessary to resolve the ambiguity. Usually the culprit is a conversion function, i.e. the ambiguity would not exist if the conversion function were not there. This is no reason to avoid conversion functions on this account. One must simply weigh the convenience of the automatic conversion against the inconvenience of explicitly resolving ambiguities.
In resolving calls to overloaded member functions, no alterations are done on the implicit first argument with the exception perhaps of some of the trivial conversions.
For linkers to be able to handle this system of function overloading, the names of functions must usually be "mangled" before being handed on to the linker. The mangled name is a new name which incorporates the old name as well as information encoded about the arguments. Most debuggers don't require a programmer to know the mangled name to access a variable. The mangled names would probably be encountered at an assembly code level.
Example: plus() family of functions.
int plus(int, int);
long plus(long, long);
float plus(float, float);
double plus(double, double);
 
short  si;
int    i;
long   li;
float  f;
double d;
 
plus(i, i);
plus(si, si);
plus(li, i);
plus(f, d);
plus(li, d);



0 comments: