C++ Basics [06]: Functions Overloading and Matching

4 minute read

Published:

Functions that have the same name but different parameter lists and that appear in the same scope are overloaded. When we call these functions, the compiler can deduce which function we want based on the argument type we pass. Here arise a question: when does two parameter lists differ?


Defining Overloaded Functions

Here is an example given in C++ primier. Although it looks like the parameter types are different in the following two pairs, each pair actually defines the same function.

Record lookup(const Account& acct);
Record lookup(const Account&);    // parameter names are ignored

typedef Phone Telno;
Record lookup(const Phone&);
Record lookup(const Telno&);      // Telno and Phone are the same type

In can be more trickier with const parameters. Parameters defiend as references/pointers to const and const pointers can behave very differently. When parameters are defined as const pointers, as the const declaration only declares the pointers to be const, the arguments passed to the function can still only be nonconstant, which is the same as plain pointers. In this way, the conpiler cannot distinguish which function to call according to the parameter lists. Therefore, the second declaration in the following example would be a mistake.

Record lookup(Phone*);
Record lookup(Phone* const);  // redeclares Record lookup(Phone*)

When parameters are defined as references to const or pointers to const, as the objects they referece/point to are constants, the compiler can use the constness of the argument to distinguish which function to call. Therefore, the following two pairs of functions would be different declarations.

Record lookup(Account&);        // function that takes a reference to Account
Record lookup(const Account&);  // new function that takes a reference to const

Record lookup(Account*);        // new function, takes a pointer to Account
Record lookup(const Account*);  // new function, takes a pointer to const

Note: Because there is no conversion from const, we can pass a const object (or a pointer to const) only to the version with a const parameter. Because there is a conversion to const, we can call either function on a nonconst object or a pointer to nonconst.

int i = 0;
const int j = 1;
int* const ptr1 = &i;       // ok
int* const ptr2 = &j;       // error: invalid conversion from 'const int*' to 'int*'
const int* ptr3 = &i;       // ok
const int* ptr4 = &j;       // ok
const int* const ptr5 = &i; // ok
const int* const ptr6 = &j; // ok

Calling Overloaded Functions

In many cases, it might be straightforward to determine whether a particular call is illegal and which function will be called. However, Determining which function is called when the overloaded functions have the same number of parameters and those parameters are related by conversions can be less obvious. As an example, consider the following set of functions and function call with a single argument:

void f();
void f(int);
void f(int, int);
void f(double, double = 3.14);
f(5.6);

The following steps will be involved to match the overloaded functions:

  1. Identify the set of overloaded functions considered for the call. In this case, there are 4 candidate functions named f.
  2. Select from the set of candidate functions that can be called with the arguments in the given call. As with any call, an argument might match its parameter either because the types match exactly or because there is a conversion from the argument type to the type of the parameter. In this case, there are two viable functions, f(int) and f(double, double = 3.4).
  3. Find the best match, if any. The idea is that the closer the types of the argument and parameter are to each other, the better the match.In this case, it is f(double, double = 3.4).

It can be more complicated when there are two and more arguments. Consider the following call with two arguments.

f(5, 5.6)

If we look at the first argument, f(int, int) would be the best match; however, if we look at the second argument, f(double, double) would be the best match. The compilerwill reject this call because it is ambiguous: Each viable function is a bettermatch than the other on one of the arguments to the call.

Casts should not be needed to call an overloaded function. The need for a cast suggests that the parameter sets are designed poorly.


Table of Contents

Comments