One
of the important features in any programming language is the convenient use of
names.
When
you create an object (a variable), you give a name to a region of storage. A
function is a name for an action. By using names that you make up to describe
the system at hand, you create a program that is easier for people to
understand and change. It’s a lot like writing prose – the goal is
to communicate with your readers.
A
problem arises when mapping the concept of nuance in
human language onto a programming language. Often, the same word expresses a
number of different meanings, depending on context. That is, a single word has
multiple meanings – it’s
overloaded.
This is very useful, especially when it comes to trivial differences. You say
“wash the shirt, wash the car.” It would be silly to be forced to
say, “shirt_wash the shirt, car_wash the car” just so the hearer
doesn’t have to make any distinction about the action performed. Most
human languages are redundant, so even if you miss a few words, you can still
determine the meaning. We don’t need unique identifiers – we can
deduce meaning from context.
Most
programming languages, however, require that you have a unique identifier for
each function. If you have three different types of data you want to print,
int,
char,
and
float,
you generally have to create three different function names, for example,
print_int( ),
print_char( ),
and
print_float( ).
This loads extra work on you as you write the program, and on readers as they
try to understand it.
In
C++, another factor forces the overloading of function names: the constructor.
Because the constructor’s name is predetermined by the name of the class,
there can be only one constructor name. But what if you want to create an
object in more than one way? For example, suppose you build a class that can
initialize itself in a standard way and also by reading information from a
file. You need two constructors, one that takes no arguments (the
default
constructor) and one that takes a character array as an argument, which is the
name of the file to initialize the object. Both are constructors, so they must
have the same name – the name of the class. Thus function overloading is
essential to allow the same function name, the constructor in this case, to be
used with different argument types.
Although
function overloading is a must for constructors, it’s a general
convenience and can be used with any function, not just class member functions.
In addition, function overloading means that if you have two libraries that
contain functions of the same name, the chances are they won’t conflict
as long as the argument lists are different. We’ll look at all these
factors in detail throughout this chapter.
The
theme of this chapter is convenient use of function names. Function overloading
allows you to use the same name for different functions, but there’s a
second way to make calling a function more convenient. What if you’d like
to call the same function in different ways? When functions have long argument
lists, it can become tedious to write and confusing to read the function calls
when most of the arguments are the same for all the calls. A very commonly used
feature in C++ is called
default
arguments.
A default argument is one the compiler inserts if the person calling a function
doesn’t specify it. Thus the calls
f(“hello”),
f(“hi”,
1)
and
f(“howdy”,
2, ‘c’)
can all be calls to the same function. They could also be calls to three
overloaded functions, but when the argument lists are this similar,
you’ll usually want similar behavior that calls for a single function.
Function
overloading and default arguments really aren’t very complicated. By the
time you reach the end of this chapter, you’ll understand when to use
them and the underlying mechanisms used during compiling and linking to
implement them.