Function Overloading

A single function name can have multiple declarations. If those declarations specify different function signatures, the function name is overloaded. A function call to an overloaded function requires the compiler to resolve the overloaded name and decide which function to call. The compiler uses the argument types (but not the return type) to resolve calls to overloaded functions. Example 5-11 shows simple examples of two overloaded functions named sqrt: one for int arguments and the other for double arguments. The rest of this section explains the rules for overloading and resolution.

Example 5-11. Overloaded functions

int sqrt(int);
double sqrt(double);

int main(  )
{
  std::cout << sqrt(3) << '\n';    // sqrt(int)
  std::cout << sqrt(3.14) << '\n'; // sqrt(double)
}

Whenever you declare more than one function with the same name in the same scope, you are overloading the function name. The function can be an ordinary function, member function, constructor, or overloaded operator.

Overloaded functions must differ in their parameter lists: they must have a different number of parameters, or the parameter types must be different. Refer to Section 5.2.2 earlier in this chapter for information on equivalent parameter types.

Default arguments are not considered when declaring overloaded functions (but are important when resolving a call to an overloaded function, as described in Section 5.3.2). Example 5-12 shows overloaded constructors and member functions for the point class, and overloaded declarations for the add function.

A function call expression (Chapter 3) must identify the function being called, based on its name and arguments. For example, the simple expression f(x) might be a call to a function named f, a function call through a function pointer named f, a function template named f, the construction of an object of class f, a conversion of x to a type named f, or the invocation of the function call operator of an object named f. In each situation, the compiler might use different rules for interpreting f and x.

The compiler first uses the function name and context to create a list of candidate functions. The number and types of the arguments are used to select the best match from the candidates, and that function is the one that is called. If no match is found, the compiler reports an error. If more than one match ties for "best," the compiler reports an ambiguity error.

For example, the C++ standard library declares three different sqrt functions (see <cmath> in Chapter 13):

float sqrt(float);
double sqrt(double);
long double sqrt(long double);

Suppose you add another function named sqrt, such as the following, to apply it to each element of an array :

void sqrt(const double data[], size_t count);

In a function call to sqrt (e.g., sqrt(x)), the compiler first uses the ordinary rules of name lookup (Chapter 2) to find the first suitable object or function named sqrt. Suppose you used using namespace std; to import the standard sqrt functions into the same namespace as your sqrt function. The compiler would collect all the overloaded sqrt functions as the candidate list, which has four elements in this case (the three original functions plus the array version). The list is then pruned to eliminate functions with the wrong number of arguments. In this case, the array version of the function is eliminated because the expression has only one argument. Finally, the type of x is used to determine which function to call. If there is an exact match, the corresponding function is called. If x is, for example, an integer, the compiler reports an error because the three floating-point sqrt functions look equally good. If x has class type, and the class has a conversion function to one of the floating-point types, the compiler implicitly calls that conversion and then calls the corresponding function:

struct FixedPoint {
  ...
  operator long double(  );
};
void demo(  )
{
  FixedPoint x;
  std::cout << sqrt(x) << '\n'; // Prints a long double
}

If a candidate is a function template, the compiler deduces the argument types (see Chapter 7), and from that point on, the template instance is treated as a normal function.

The rules for creating the candidate list and argument list depend on the context of the function call. The argument list can also depend on context: when choosing an overloaded function to call, a member function's class is treated as an argument type. More precisely, member functions have an implicit object parameter whose type is a reference to T, in which T is the class that defines the member function. Any qualifiers on the member function also qualify the type (that is, the object type for a const function is const T &). In the function body, the type of this is a pointer to qualified T. (See Chapter 6 for more information about this.)

A call to a member function applies to a specific object, which is the implicit object argument. When calling a member function with the -> or . operator, the implicit object argument is the left operand. For an overloaded binary operator (such as operator<<), the implicit object argument is the left operand. For a unary operator, the implicit object argument is the operand. When calling an unqualified function inside a nonstatic member function, the implicit object argument is *this. The implicit object argument is considered the first argument in the argument list. Unlike normal arguments, implicit type conversions do not take place for the implicit object argument.

This section describes how the compiler creates its list of candidate functions. Table 5-1 summarizes the various categories of function calls, and the subsequent subsections provide the details.

An expression that uses the . or -> operator to call a function must call a member function. The function name is looked up in the class of the left operand and in its base classes (using the name lookup rules listed in Chapter 2). The search starts in the most-derived class. If that class declares a member function with the desired name, the search stops, and the candidate functions are all the member functions with the same name in that class. If no matching member function is found, the search continues with the immediate base classes. The search stops when a matching name is found.

In other words, a derived class cannot overload a function that is declared in a base class. Instead, if the derived class has a function with the same name, the derived class hides the name that would be inherited from the base class (or the derived class might override a virtual function; see Chapter 6). Insert a using declaration in the derived class if you want the compiler to consider the base class functions as candidates, as shown in Example 5-13.

If a class has multiple immediate base classes, overload resolution must find a name in only one of the base classes. If functions with the desired name are found in multiple immediate base classes, the compiler reports an ambiguity error. To resolve this ambiguity, use the scope operator (::) to qualify the function name in the derived class, as shown in Example 5-14.

An ordinary-looking function call can be a nonmember function, a member function, an object of class type, a type name, or a variable of type pointer-to-function. For a variable of type pointer-to-function, overload resolution takes place when a value is assigned to the variable (discussed later in this chapter). In the other cases, the usual name lookup rules apply when finding the candidate functions.

A function call in a member function searches first for matching member functions in the same class or an ancestor class. The search for a match begins in the class that is declaring the member function. If a match is found, candidate functions are taken from that class. If no matches are found, the search continues with ancestor classes, following the same rules as for qualified member function calls. If no matches are found in any ancestor classes, the namespace of the class is searched for nonmember functions. Example 5-15 shows how a matching member function in a base class precludes finding a better match in the global namespace.

If a function call expression resolves to an object of class type, the class must have a function call operator or a conversion operator, in which the conversion is to a function type: pointer-to-function, reference-to-function, or reference-to-pointer-to function.

A conversion operator is rarely used. The compiler constructs a wrapper function so that the conversion function is the first argument. The conversion type followed by the types of the actual arguments is the new list of argument types to use in overload resolution. In other words, all of a class's function-type conversion operators participate in overload resolution.

Example 5-16 shows how a class-type object is used as the left operand of a function call.

The function for an overloaded operator is chosen according to the usual rules for resolving overloaded functions, in which the operator's operands are the function's arguments. You can overload operators only if at least one operand has a user-defined type. If all operands have built-in types, an operator has its built-in meaning.

If the left operand of an operator has class type, the operator can be a nonstatic member function or a nonmember function. Otherwise, the function must be a nonmember function. The operator function name is formed from the keyword operator followed by the operator symbol, e.g., operator[], operator++, or operator-. Unary operators can be member functions with no arguments or nonmember functions of one argument. Binary operators are member functions of one argument or nonmember functions of two arguments. Postfix increment and decrement operators are different. They are implemented as binary operators for which the right operand is an int. (See Chapter 3 for more information.)

The -> operator is also different. Although it is a binary operator, it is treated as a unary operator. It must be implemented as a member function, so the function takes no arguments. It returns a pointer or another object that overloads the -> operator. Ultimately, the overloaded operators must resolve to a pointer of class type, to which the built-in -> operator can be applied.

The candidate functions for the overloaded operator include all member, nonmember, and built-in candidate functions. Member functions do not take precedence over nonmember functions.

Example 5-17 shows how operator functions are different from named functions. In particular, it shows how operators are resolved by considering member functions and global functions, whereas named member functions take precedence over named global functions.

An object can be initialized using function-like syntax (see Chapter 2). When an object of class type is so initialized, the candidate functions are constructors of the named class. The same syntax applies to conversion initialization covered later in this chapter. Example 5-18 shows function-like initializers that call an overloaded constructor.

When taking the address of a function, the compiler does not have the benefit of an argument list to help resolve overloading. Instead, it collects a list of candidate functions and picks one based on the type required by the context. The context can be an initializer, an assignment, a function argument, the return value of a function, or an explicit type cast.

Of the potentially matching functions, nontemplate functions are better than template functions, and more-specific template functions are better than less-specific template functions. There must be exactly one best function, or else the compiler reports an error. Example 5-22 shows simple examples of resolving the addresses of overloaded functions.

Once the compiler has found the list of candidate functions, it must choose the "best" match from the list. The candidate list is first pruned by removing functions with the wrong number of arguments. Then the remaining functions are checked to determine how to convert the actual arguments to the desired parameter types. The function with the simplest conversions wins. This section discusses these two steps.

Once the compiler has assembled its list of candidate functions, it prunes the list by removing functions that have the wrong number of arguments. If the function call has n argument expressions, a function is kept in the list if any of the following apply:

Also, each actual argument must be convertible (applying the rules described in the next section) to the parameter type.

An actual argument is implicitly converted to the desired parameter type by undergoing a series of transformations. Basically, a better conversion is one in which the argument type is closer to the parameter type and, therefore, the type undergoes fewer transformations.

A standard conversion sequence is a sequence of built-in transformations that are based on automatic type conversions (Chapter 3). A sequence is built from at most one of each of three kinds of transformations. The quality of a standard conversion sequence is dictated by its worst transformation, in which the value-preserving transformations are better than those that might discard information. The transformations are as follows, ordered from best to worst:

A user-defined conversion sequence has up to three parts: a standard conversion sequence followed by a single, user-defined conversion (constructor or type conversion operator) followed by another standard conversion sequence.

A standard conversion sequence is better than a user-defined conversion sequence. A user-defined conversion sequence is better than matching an ellipsis parameter.

If one sequence of transformations is a subsequence of another, the shorter sequence is better than the longer one.

Among sequences that differ only by qualification, the one with fewer qualification adjustments is better than one with more adjustments.

Example 5-23 shows how overloaded functions are chosen. Notice that type promotions are preferred to the conversion to Num, even though Num has an exact type conversion to long. Also note how an unsigned long cannot be promoted, so it must undergo a built-in conversion. The compiler has no preference of int, long or double, so the conversion is ambiguous and, therefore, results in an error. The same applies to long double; even though you might consider the conversion to double to be "better" than conversion to int, the rules of overloading say otherwise. The final example results in an error because there is no matching function. An array of wchar_t cannot be converted to any of the types used as func parameters.