Professional C__ - Marc Gregoire [96]
For the second line, the compiler will convert the double value (1.23) to an integer value (1) and then call foo(int i). The compiler might give you a warning, but it will perform this implicit conversion. You can prevent the compiler from performing this conversion by explicitly deleting a double instance of foo():
class MyClass
{
public:
void foo(int i);
void foo(double d) = delete;
};
With this change, an attempt to call foo() with a double will be flagged as an error by the compiler, instead of performing a conversion to an integer.
Default Parameters
A feature similar to method overloading in C++ is default parameters. You can specify defaults for function and method parameters in the prototype. If the user specifies those arguments, the defaults are ignored. If the user omits those arguments, the default values are used. There is a limitation, though: You can only provide defaults for a continuous list of parameters starting from the rightmost parameter. Otherwise, the compiler would not be able to match missing arguments to default parameters. Default parameters are most useful in constructors. For example, you can assign default values to the width and height in your Spreadsheet constructor:
class Spreadsheet
{
public:
Spreadsheet(const SpreadsheetApplication& theApp,
int inWidth = kMaxWidth, int inHeight = kMaxHeight);
// Omitted for brevity
};
Code snippet from SpreadsheetDefaultParams\Spreadsheet.h
The implementation of the Spreadsheet constructor stays the same. Note that you specify the default parameters only in the method declaration, but not in the definition.
Now you can call the Spreadsheet constructor with one, two, or three arguments even though there is only one non-copy constructor:
SpreadsheetApplication theApp;
Spreadsheet s1(theApp);
Spreadsheet s2(theApp, 5);
Spreadsheet s3(theApp, 5, 6);
Code snippet from SpreadsheetDefaultParams\SpreadsheetTest.cpp
A constructor with defaults for all its parameters can function as a default constructor. That is, you can construct an object of that class without specifying any arguments. If you try to declare both a default constructor and a multi-argument constructor with defaults for all its parameters, the compiler will complain because it won’t know which constructor to call if you don’t specify any arguments.
Note that anything you can do with default parameters you can do with method overloading. You could write three different constructors, each of which takes a different number of parameters. However, default parameters allow you to write only one constructor to take three different numbers of arguments. You should use the mechanism with which you are most comfortable.
Inline Methods
C++ gives you the ability to recommend that a call to a method or function should not actually be implemented in the generated code as a call to a separate block of code. Instead, the compiler should insert the method or function body directly into the code where the method or function call is made. This process is called inlining, and methods or functions that want this behavior are called inline methods or functions. Inlining is safer than using #define macros.
You can specify an inline method or function by placing the inline keyword in front of its name in the function or method definition. For example, you might want to make the accessor methods of the SpreadsheetCell class inline, in which case you would define them like this:
inline double SpreadsheetCell::getValue() const
{
mNumAccesses++;
return mValue;
}
inline string SpreadsheetCell::getString() const
{
mNumAccesses++;
return mString;
}
Code snippet from SpreadsheetCellMethods\SpreadsheetCell.h
Now, the compiler has the option to replace calls to getValue() and getString() with the actual method body instead of generating code to make a function call.
There is one caveat: Definitions of inline methods and functions must be available in every source file in which they are called. That makes sense if you think about it: How can the compiler substitute the function body