In many cases, functions have a number of arguments that are used so infrequently that a default value would suffice. To address this, the default-argument facility allows for specifying only those arguments to a function that are meaningful in a given call. To illustrate this concept, consider the example presented in “Function Overloading”.
// Prototype three print functions.
int print( char *s ); // Print a string.
int print( double dvalue ); // Print a double.
int print( double dvalue, int prec ); // Print a double with a
// given precision.
In many applications, a reasonable default can be supplied for prec, eliminating the need for two functions:
// Prototype two print functions.
int print( char *s ); // Print a string.
int print( double dvalue, int prec=2 ); // Print a double with a
// given precision.
The implementation of the print function is changed slightly to reflect the fact that only one such function exists for type double:
// Print a double in specified precision.
// Positive numbers for precision indicate how many digits
// precision after the decimal point to show. Negative
// numbers for precision indicate where to round the number
// to the left of the decimal point.
int print( double dvalue, int prec )
{
// Use table-lookup for rounding/truncation.
static const double rgPow10[] = {
10E-7, 10E-6, 10E-5, 10E-4, 10E-3, 10E-2, 10E-1, 10E0,
10E1, 10E2, 10E3, 10E4, 10E5, 10E6
};
const int iPowZero = 6;
// If precision out of range, just print the number.
if( prec >= -6 || prec <= 7 )
// Scale, truncate, then rescale.
dvalue = floor( dvalue / rgPow10[iPowZero - prec] ) *
rgPow10[iPowZero - prec];
cout << dvalue << endl;
return cout.good();
}
To invoke the new print function, use code such as the following:
print( d ); // Precision of 2 supplied by default argument.
print( d, 0 ); // Override default argument to achieve other
// results.
There are several points to note when using default arguments:
Default arguments are used only in function calls where trailing arguments are omitted—they must be the last argument(s). Therefore, the following code is illegal:
int print( double dvalue = 0.0, int prec );
A default argument cannot be redefined in later declarations even if the redefinition is identical to the original. Therefore, the following code produces an error:
// Prototype for print function.
int print( double dvalue, int prec = 2 );
...
// Definition for print function.
int print( double dvalue, int prec = 2 )
{
...
}
The problem with the preceding code is that the function declaration in the definition redefines the default argument for prec.
Additional default arguments can be added by later declarations.
Default arguments can be provided for pointers to functions. For example:
int (*pShowIntVal)( int i = 0 );
The expressions used for default arguments are often constant expressions, but this is not a requirement. The expression can combine functions that are visible in the current scope, constant expressions, and global variables. The expression cannot contain local variables or nonstatic class-member variables. The following code illustrates this:
BOOL CreateVScrollBar( HWND hWnd, short nWidth =
GetSystemMetrics( SM_CXVSCROLL ) );
The preceding declaration specifies a function that creates a vertical scroll bar of a given width for a window. If no width argument is supplied, the Windows API function, GetSystemMetrics, is called to find the default width for a scroll bar.
The default expression is not evaluated until the function call, but the evaluation is completed before the function call actually takes place.
Because formal arguments to a function are in function scope, and because the evaluation of default arguments takes place prior to entry to this scope, formal arguments cannot be used in default argument expressions. Use of local variables in default argument expressions is also disallowed.
Note that any formal argument declared prior to a default argument expression can potentially hide a global name in the function scope, which can cause errors. The following code is illegal:
const int Categories = 9;
void EnumCategories( char *Categories[], int n = Categories );
In the preceding code, the global name Categories is hidden at function scope, making the default argument expression invalid.
The default argument is not considered part of the function type. Therefore, it is not used in selecting overloaded functions. Two functions that differ only in their default arguments are considered multiple definitions rather than overloaded functions.
Default arguments cannot be supplied for overloaded operators.