When to Use Function Overloading

You might find function overloading fascinating, but you shouldn’t overuse it. You should reserve function overloading for functions that perform basically the same task but with different forms of data. Also you might want to check whether you can accomplish the same end by using default arguments. For example, you could replace the single, string-oriented left() function with two overloaded functions:

char * left(const char * str, unsigned n);   // two arguments
char * left(const char * str);               // one argument

But using the single function with a default argument is simpler. There’s just one function to write instead of two, and the program requires memory for just one function instead of two. If you decide to modify the function, you have to edit only one. However, if you require different types of arguments, default arguments are of no avail, so in that case, you should use function overloading.

Function Templates

Contemporary C++ compilers implement one of the newer C++ additions: function templates. A function template is a generic function description; that is, it defines a function in terms of a generic type for which a specific type, such as int or double, can be substituted. By passing a type as a parameter to a template, you cause the compiler to generate a function for that particular type. Because templates let you program in terms of a generic type instead of a specific type, the process is sometimes termed generic programming. Because types are represented by parameters, the template feature is sometimes referred to as parameterized types. Let’s see why such a feature is useful and how it works.

Earlier Listing 8.4 defined a function that swapped two int values. Suppose you want to swap two double values instead. One approach is to duplicate the original code but replace each int with double. If you need to swap two char values, you can use the same technique again. Still, it’s wasteful of your valuable time to have to make these petty changes, and there’s always the possibility of making an error. If you make the changes by hand, you might overlook an int. If you do a global search-and-replace to substitute, say, double for int, you might do something such as converting

int x;
short interval;

to the following:

double x;            // intended change of type
short doubleerval;   // unintended change of variable name

C++’s function template capability automates the process, saving you time and providing greater reliability.

Function templates enable you to define a function in terms of some arbitrary type. For example, you can set up a swapping template like this:

template <typename AnyType>
void Swap(AnyType &a, AnyType &b)
{
    AnyType temp;
    temp = a;
    a = b;
    b = temp;
}

The first line specifies that you are setting up a template and that you’re naming the arbitrary type AnyType. The keywords template and typename are obligatory, except that you can use the keyword class instead of typename. Also you must use the angle brackets. The type name (AnyType, in this example) is your choice, as long as you follow the usual C++ naming rules; many programmers use simple names such as T, which, one must admit, is simple indeed. The rest of the code describes the algorithm for swapping two values of type AnyType. The template does not create any functions. Instead, it provides the compiler with directions about how to define a function. If you want a function to swap ints, then the compiler creates a function following the template pattern, substituting int for AnyType. Similarly, if you need a function to swap doubles, the compiler follows the template, substituting the double type for AnyType.

Before the C++98 Standard added the keyword typename to the language, C++ used the keyword class in this particular context. That is, you can write the template definition this way:

template <class AnyType>
void Swap(AnyType &a, AnyType &b)
{
    AnyType temp;
    temp = a;
    a = b;
    b = temp;
}

The typename keyword makes it a bit more obvious that the parameter AnyType represents a type; however, large libraries of code have already been developed by using the older keyword class. The C++ Standard treats the two keywords identically when they are used in this context. This book uses both forms so that you will be familiar with them when encountering them elsewhere.


Tip

You should use templates if you need functions that apply the same algorithm to a variety of types. If you aren’t concerned with backward compatibility and can put up with the effort of typing a longer word, you can use the keyword typename rather than class when you declare type parameters.


To let the compiler know that you need a particular form of swap function, you just use a function called Swap() in your program. The compiler checks the argument types you use and then generates the corresponding function. Listing 8.11 shows how this works. The program layout follows the usual pattern for ordinary functions, with a template function prototype near the top of the file and the template function definition following main(). The example follows the more usual practice of using T instead of AnyType as the type parameter.

Listing 8.11. funtemp.cpp


// funtemp.cpp -- using a function template
#include <iostream>
// function template prototype
template <typename T>  // or class T
void Swap(T &a, T &b);

int main()
{
    using namespace std;
    int i = 10;
    int j = 20;
    cout << "i, j = " << i << ", " << j << ". ";
    cout << "Using compiler-generated int swapper: ";
    Swap(i,j);  // generates void Swap(int &, int &)
    cout << "Now i, j = " << i << ", " << j << ". ";

    double x = 24.5;
    double y = 81.7;
    cout << "x, y = " << x << ", " << y << ". ";
    cout << "Using compiler-generated double swapper: ";
    Swap(x,y);  // generates void Swap(double &, double &)
    cout << "Now x, y = " << x << ", " << y << ". ";
    // cin.get();
    return 0;
}

// function template definition
template <typename T>  // or class T
void Swap(T &a, T &b)
{
    T temp;   // temp a variable of type T
    temp = a;
    a = b;
    b = temp;
}


The first Swap() function in Listing 8.11 has two int arguments, so the compiler generates an int version of the function. That is, it replaces each use of T with int, producing a definition that looks like this:

void Swap(int &a, int &b)
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}

You don’t see this code, but the compiler generates and then uses it in the program. The second Swap() function has two double arguments, so the compiler generates a double version. That is, it replaces T with double, generating this code:

void Swap(double &a, double &b)
{
    double temp;
    temp = a;
    a = b;
    b = temp;
}

Here’s the output of the program in Listing 8.11, which shows that the process has worked:

i, j = 10, 20.
Using compiler-generated int swapper:
Now i, j = 20, 10.
x, y = 24.5, 81.7.
Using compiler-generated double swapper:
Now x, y = 81.7, 24.5.

Note that function templates don’t make executable programs any shorter. In Listing 8.11, you still wind up with two separate function definitions, just as you would if you defined each function manually. And the final code doesn’t contain any templates; it just contains the actual functions generated for the program. The benefits of templates are that they make generating multiple function definitions simpler and more reliable.

More typically, templates are placed in a header file that is then included in the file using them. Chapter 9 discusses header files.

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

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