Regardless of your programming background, C++ is likely to take a
little getting used to. It’s a powerful language with an enormous range
of features, but before you can harness that power and make effective
use of those features, you have to accustom yourself to C++’s way of
doing things. This entire book is about how to do that, but some
things are more fundamental than others, and this chapter is about
some of the most fundamental things of all. Item 1: View C++ as a federation of languages.
In the beginning, C++ was just C with some object-oriented features
tacked on. Even C++’s original name, “C with Classes,” reflected this
As the language matured, it grew bolder and more adventurous,
adopting ideas, features, and programming strategies different from
those of C with Classes. Exceptions required different approaches to
structuring functions (see Item 29). Templates gave rise to new ways
of thinking about design (see Item 41), and the STL defined an
approach to extensibility unlike any most people had ever seen.
Today’s C++ is a multiparadigm programming language, one supporting a combination of procedural, object-oriented, functional, generic,
and metaprogramming features. This power and flexibility make C++
a tool without equal, but can also cause some confusion. All the
“proper usage” rules seem to have exceptions. How are we to make
sense of such a language?
The easiest way is to view C++ not as a single language but as a federation of related languages. Within a particular sublanguage, the rules
tend to be simple, straightforward, and easy to remember. When you
move from one sublanguage to another, however, the rules may
change. To make sense of C++, you have to recognize its primary sublanguages. Fortunately, there are only four:
■ C. Way down deep, C++ is still based on C. Blocks, statements, the
preprocessor, built-in data types, arrays, pointers, etc., all come
from C. In many cases, C++ offers approaches to problems that
are superior to their C counterparts (e.g., see Items 2 (alternatives
to the preprocessor) and 13 (using objects to manage resources)),
but when you find yourself working with the C part of C++, the
rules for effective programming reflect C’s more limited scope: no
templates, no exceptions, no overloading, etc.
■ Object-Oriented C++. This part of C++ is what C with Classes was
all about: classes (including constructors and destructors), encapsulation, inheritance, polymorphism, virtual functions (dynamic
binding), etc. This is the part of C++ to which the classic rules for
object-oriented design most directly apply.
■ Template C++. This is the generic programming part of C++, the
one that most programmers have the least experience with. Template considerations pervade C++, and it’s not uncommon for rules
of good programming to include special template-only clauses
(e.g., see Item 46 on facilitating type conversions in calls to template functions). In fact, templates are so powerful, they give rise
to a completely new programming paradigm, template metaprogramming (TMP). Item 48 provides an overview of TMP, but unless
you’re a hard-core template junkie, you need not worry about it.
The rules for TMP rarely interact with mainstream C++ programming.
■ The STL. The STL is a template library, of course, but it’s a very
special template library. Its conventions regarding containers, iterators, algorithms, and function objects mesh beautifully, but templates and libraries can be built around other ideas, too. The STL
has particular ways of doing things, and when you’re working with
the STL, you need to be sure to follow its conventions.
Keep these four sublanguages in mind, and don’t be surprised when
you encounter situations where effective programming requires that
you change strategy when you switch from one sublanguage to
another. For example, pass-by-value is generally more efficient than
pass-by-reference for built-in (i.e., C-like) types, but when you move
from the C part of C++ to Object-Oriented C++, the existence of userdefined constructors and destructors means that pass-by-referenceto-const is usually better. This is especially the case when working in
Template C++, because there, you don’t even know the type of object
Accustoming Yourself to C++ Item 2 13
you’re dealing with. When you cross into the STL, however, you know
that iterators and function objects are modeled on pointers in C, so for
iterators and function objects in the STL, the old C pass-by-value rule
applies again. (For all the details on choosing among parameter-passing options, see Item 20.)
C++, then, isn’t a unified language with a single set of rules; it’s a federation of four sublanguages, each with its own conventions. Keep
these sublanguages in mind, and you’ll find that C++ is a lot easier to
Things to Remember
✦ Rules for effective C++ programming vary, depending on the part of
C++ you are using. Item 2: Prefer consts, enums, and inlines to #defines.
This Item might better be called “prefer the compiler to the preprocessor,” because #define may be treated as if it’s not part of the language
per se. That’s one of its problems. When you do something like this,
#define ASPECT_RATIO 1.653
the symbolic name ASPECT_RATIO may never be seen by compilers; it
may be removed by the preprocessor before the source code ever gets
to a compiler. As a result, the name ASPECT_RATIO may not get entered
into the symbol table. This can be confusing if you get an error during
compilation involving the use of the constant, because the error message may refer to 1.653, not ASPECT_RATIO. If ASPECT_RATIO were
defined in a header file you didn’t write, you’d have no idea where that
1.653 came from, and you’d waste time tracking it down. This problem
can also crop up in a symbolic debugger, because, again, the name
you’re programming with may not be in the symbol table.
The solution is to replace the macro with a constant:
const double AspectRatio = 1.653; // uppercase names are usually for
// macros, hence the name change
As a language constant, AspectRatio is definitely seen by compilers and
is certainly entered into their symbol tables. In addition, in the case of
a floating point constant (such as in this example), use of the constant
may yield smaller code than using a #define. That’s because the preprocessor’s blind substitution of the macro name ASPECT_RATIO with
1.653 could result in multiple copies of 1.653 in your object code,
while the use of the constant AspectRatio should never result in more
than one copy.