6.16 Function Overloading

C++ enables several functions of the same name to be defined, as long as they have different signatures. This is called function overloading. The C++ compiler selects the proper function to call by examining the number, types and order of the arguments in the call. Function overloading is used to create several functions of the same name that perform similar tasks, but on different data types. For example, many functions in the math library are overloaded for different numeric types—the C++ standard requires float, double and long double overloaded versions of the math library functions discussed in Section 6.3.

Good Programming Practice 6.6

Overloading functions that perform closely related tasks can make programs more readable and understandable.

Overloaded square Functions

Figure 6.20 uses overloaded square functions to calculate the square of an int (lines 7–10) and the square of a double (lines 13–16). Line 19 invokes the int version of function square by passing the literal value 7. C++ treats whole-number literal values as type int. Similarly, line 21 invokes the double version of function square by passing the literal value 7.5, which C++ treats as a double. In each case the compiler chooses the proper function to call, based on the type of the argument. The last two lines of the output window confirm that the proper function was called in each case.

Fig. 6.20 Overloaded square functions

Alternate View

 1   // Fig. 6.20: fig06_20.cpp
 2   // Overloaded square functions.
 3   #include <iostream>
 4   using namespace std;
 5
 6   // function square for int values
 7   int square(int x) {
 8      cout << "square of integer " << x << " is ";
 9      return x * x;
10   }
11
12   // function square for double values
13   double square(double y) {
14      cout << "square of double " << y << " is ";
15      return y * y;
16   }
17
18   int main() {
19      cout << square(7); // calls int version
20      cout << endl;
21      cout << square(7.5); // calls double version
22      cout << endl;
23   }

square of integer 7 is 49
square of double 7.5 is 56.25

How the Compiler Differentiates Among Overloaded Functions

Overloaded functions are distinguished by their signatures. A signature is a combination of a function’s name and its parameter types (in order). The compiler encodes each function identifier with the types of its parameters (sometimes referred to as name mangling or name decoration) to enable type-safe linkage. Type-safe linkage ensures that the proper overloaded function is called and that the types of the arguments conform to the types of the parameters. Figure 6.21 was compiled with GNU C++. Rather than showing the execution output of the program (as we normally would), we show the mangled function names produced in assembly language by GNU C++.

For GNU C++, each mangled name (other than main) begins with two underscores (__) followed by the letter Z, a number and the function name. The number that follows Z specifies how many characters are in the function’s name. For example, function square

Fig. 6.21 Name mangling to enable type-safe linkage.

Alternate View

 1   // Fig. 6.21: fig06_21.cpp
 2   // Name mangling to enable type-safe linkage.
 3
 4   // function square for int values
 5   int square(int x) {
 6      return x * x;
 7   }
 8
 9   // function square for double values
10   double square(double y) {
11      return y * y;
12   }
13
14   // function that receives arguments of types
15   // int, float, char and int&
16   void nothing1(int a, float b, char c, int& d) { }
17
18   // function that receives arguments of types
19   // char, int, float& and double&
20   int nothing2(char a, int b, float& c, double& d) {
21      return 0;
22   }
23
24   int main() { }

__Z6squarei
__Z6squared
__Z8nothing1ifcRi
__Z8nothing2ciRfRd
main

has 6 characters in its name, so its mangled name is prefixed with __Z6. Following the function name is an encoding of its parameter list:

  • For function square that receives an int (line 5), i represents int, as shown in the output’s first line.

  • For function square that receives a double (line 10), d represents double, as shown in the output’s second line.

  • For function nothing1 (line 16), i represents an int, f represents a float, c represents a char and Ri represents an int& (i.e., a reference to an int), as shown in the output’s third line.

  • For function nothing2 (line 20), c represents a char, i represents an int, Rf represents a float& and Rd represents a double&.

The compiler distinguishes the two square functions by their parameter lists—one specifies i for int and the other d for double. The return types of the functions are not specified in the mangled names. Overloaded functions can have different return types, but if they do, they must also have different parameter lists. Function-name mangling is compiler specific. For example, Visual C++ produces the name square@@YAHH@Z for the square function at line 5. The GNU C++ compiler did not mangle main’s name; however, some compilers do. For example, Visual C++ uses _main.

Common Programming Error 6.9

Creating overloaded functions with identical parameter lists and different return types is a compilation error.

The compiler uses only the parameter lists to distinguish between overloaded functions. Such functions need not have the same number of parameters. Use caution when overloading functions with default parameters, because this may cause ambiguity.

Common Programming Error 6.10

A function with default arguments omitted might be called identically to another overloaded function; this is a compilation error. For example, having a program that contains both a function that explicitly takes no arguments and a function of the same name that contains all default arguments results in a compilation error when an attempt is made to use that function name in a call passing no arguments. The compiler cannot determine which version of the function to choose.

Overloaded Operators

In Chapter 10, we discuss how to overload operators to define how they should operate on objects of user-defined data types. (In fact, we’ve been using many overloaded operators to this point, including the stream insertion << and the stream extraction >> operators, which are overloaded for all the fundamental types. We say more about overloading << and >> to be able to handle objects of user-defined types in Chapter 10.)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset