MFC Programmer's SourceBook : Thinking in C++
Bruce Eckel's Thinking in C++, 2nd Ed Contents | Prev | Next

Default arguments

Examine the two constructors for Stash( ). They don’t seem all that different, do they? In fact, the first constructor seems to be the special case of the second one with the initial size set to zero. In this situation it seems a bit of a waste of effort to create and maintain two different versions of a similar function.

C++ provides a remedy with default arguments. A default argument is a value given in the declaration that the compiler automatically inserts if you don’t provide a value in the function call. In the Stash example, we can replace the two functions:

  Stash(int size); // Zero quantity
  Stash(int size, int quantity); 

with the single declaration

Stash(int size, int quantity = 0);

The Stash(int) definition is simply removed – all that is necessary is the single Stash(int, int) definition.

Now, the two object definitions

Stash A(100), B(100, 0);

will produce exactly the same results. The identical constructor is called in both cases, but for A, the second argument is automatically substituted by the compiler when it sees the first argument is an int and there is no second argument. The compiler has seen the default argument, so it knows it can still make the function call if it substitutes this second argument, which is what you’ve told it to do by making it a default.

Default arguments are a convenience, as function overloading is a convenience. Both features allow you to use a single name in different situations. The difference is that the compiler is substituting arguments when you don’t want to put them in yourself. The preceding example is a good place to use default arguments instead of function overloading; otherwise you end up with two or more functions that have similar signatures and similar behaviors. Obviously, if the functions have very different behaviors, it usually doesn’t make sense to use default arguments.

There are two rules you must be aware of when using default arguments. First, only trailing arguments may be defaulted. That is, you can’t have a default argument followed by a nondefault argument. Second, once you start using default arguments, all the remaining arguments must be defaulted. (This follows from the first rule.)

Default arguments are only placed in the declaration of a function, which is placed in a header file. The compiler must see the default value before it can use it. Sometimes people will place the commented values of the default arguments in the function definition, for documentation purposes

void fn(int x /* = 0 */) { // ...

Default arguments can make arguments declared without identifiers look a bit funny. You can end up with

void f(int x, int = 0, float = 1.1);

In C++ you don’t need identifiers in the function definition, either:

void f(int x, int, float f) { /* ... */ }

In the function body, x and f can be referenced, but not the middle argument, because it has no name. The calls must still use a placeholder, though: f(1) or f(1,2,3.0). This syntax allows you to put the argument in as a placeholder without using it. The idea is that you might want to change the function definition to use it later, without changing all the function calls. Of course, you can accomplish the same thing by using a named argument, but if you define the argument for the function body without using it, most compilers will give you a warning message, assuming you’ve made a logical error. By intentionally leaving the argument name out, you suppress this warning.

More important, if you start out using a function argument and later decide that you don’t need it, you can effectively remove it without generating warnings, and yet not disturb any client code that was calling the previous version of the function.

Contents | Prev | Next


Go to CodeGuru.com
Contact: webmaster@codeguru.com
© Copyright 1997-1999 CodeGuru