Professional C__ - Marc Gregoire [97]
Advanced C++ compilers do not require you to put definitions of inline methods in a header file. For example, Microsoft Visual C++ supports Link-Time Code Generation (LTCG) which will automatically inline small function bodies, even if they are not declared as inline and even if they are not defined in a header file. When you use such a compiler, make use of it, and don’t put the definitions in the header file. This way, your interface files stay clean without any implementation details visible in it.
C++ provides an alternate syntax for declaring inline methods that doesn’t use the inline keyword at all. Instead, you place the method definition directly in the class definition. Here is a SpreadsheetCell class definition with this syntax:
class SpreadsheetCell
{
public:
// Omitted for brevity
double getValue() const {mNumAccesses++; return mValue; }
string getString() const {mNumAccesses++; return mString; }
// Omitted for brevity
};
Code snippet from SpreadsheetCellMethods\SpreadsheetCell.h
If you single-step with a debugger on a function call that is inlined, some advanced C++ debuggers will jump to the actual source code of the inline function in the header file, giving you the illusion of a function call, but in reality, the code is inlined.
Many C++ programmers discover the inline method syntax and employ it without understanding the ramifications of making a method inline. First, there are many restrictions on which methods can be inline. Compilers will only inline the simplest methods and functions. If you define an inline method that the compiler doesn’t want to inline, it may silently ignore the directive. Second, big inline methods can lead to code bloat. The body of the methods are reproduced everywhere they are called, increasing the size of your program executable.
Modern compilers like Microsoft Visual C++ will take metrics like code bloat into account before deciding to inline a method, and they will not inline anything that is not cost-effective.
NESTED CLASSES
Class definitions can contain more than just methods and members. You can also write nested classes and structs, declare typedefs, or create enumerated types. Anything declared inside a class is in the scope of that class. If it is public, you can access it outside the class by scoping it with the ClassName:: scope resolution syntax.
You can provide a class definition inside another class definition. For example, you might decide that the SpreadsheetCell class is really part of the Spreadsheet class. You could define both of them like this:
class Spreadsheet
{
public:
class SpreadsheetCell
{
public:
SpreadsheetCell();
SpreadsheetCell(double initialValue);
// Omitted for brevity
protected:
double mValue;
string mString;
mutable int mNumAccesses;
};
Spreadsheet(const SpreadsheetApplication& theApp,
int inWidth = kMaxWidth, int inHeight = kMaxHeight);
Spreadsheet(const Spreadsheet& src);
~Spreadsheet();
// Remainder of Spreadsheet declarations omitted for brevity
};
Code snippet from NestedClasses\Spreadsheet.h
Now, the SpreadsheetCell class is defined inside the Spreadsheet class, so anywhere you refer to a SpreadsheetCell outside of the Spreadsheet class you must qualify the name with the Spreadsheet:: scope. This applies even to the method definitions. For example, the default constructor now looks like this:
Spreadsheet::SpreadsheetCell::SpreadsheetCell() : mValue(0), mNumAccesses(0)
{
}
Code snippet from NestedClasses\Spreadsheet.cpp
This syntax can quickly become clumsy. For example, the definition of the SpreadsheetCell assignment operator now looks like this:
Spreadsheet::SpreadsheetCell& Spreadsheet::SpreadsheetCell::operator=(