CPP Pocket Reference PDF
CPP Pocket Reference PDF
Pocket Reference
Kyle Loudon
Printing History:
May 2003: First Edition.
0-596-00496-6
[C] [6/06]
Contents
Introduction 1
Typographic Conventions 2
Acknowledgments 2
Compatibility with C 2
Program Structure 3
Startup 3
Termination 5
Header Files 5
Source Files 7
Preprocessor Directives 8
Preprocessor Macros 11
Fundamental Types 12
bool 12
char and wchar_t 13
short, int, long 15
float, double, long double 16
Compound Types 17
Enumerations 18
Arrays 19
Strings 22
Pointers 24
Pointers to Members 26
v
References 27
Class Types 28
Type Conversions and Definitions 28
Type Conversions 28
Type Definitions 31
Lexical Elements 31
Comments 32
Identifiers 32
Reserved Words 33
Literals 34
Operators 34
Expressions 46
Scope 47
Local Scope 47
Class Scope 47
Namespace Scope 48
File Scope 48
Other Scopes 49
Enclosing Scopes 49
Declarations 50
Declaring Variables 51
Declaring Functions 52
Storage Classes 55
Qualifiers 57
Statements 59
Expression Statements 59
Null Statements 59
Compound Statements 59
Iteration Statements 60
vi | Contents
Selection Statements 62
Jump Statements 64
Namespaces 66
using Declarations 67
using Directives 67
Unnamed Namespaces 68
Classes, Structs, and Unions 68
Declaring Objects 69
Accessing Members 69
Declaring Data Members 70
Declaring Member Functions 74
Access Levels for Members 78
Friends 79
Constructors 80
Destructors 83
Nested Declarations 85
Forward Declarations 86
Structs 86
Unions 86
Inheritance 88
Constructors and Inheritance 89
Destructors and Inheritance 90
Virtual Member Functions 91
Abstract Base Classes 94
Access Levels for Inheritance 94
Multiple Inheritance 95
Virtual Base Classes 97
Templates 98
Template Classes 98
Template Functions 101
Contents | vii
Overloading 104
Overloading Functions 104
Overloading Operators 105
Memory Management 108
Memory Allocation 108
Memory Reclamation 110
Casts and Runtime Type Information 112
C-Style Casts 112
Casts in C++ 112
Runtime Type Information 115
Exception Handling 117
try 117
throw 117
catch 118
Exception Specifications 119
The C++ Standard Library 120
The std Namespace 121
C Standard Library Support 121
C++ Standard Header Files 122
I/O Streams 122
viii | Contents
Chapter 1
Introduction
The C++ Pocket Reference is a quick reference to the C++
programming language as defined by the international stan-
dard INCITS/ISO/IEC 14882–1998. It consists of a number
of short sections, each further divided into specific topics.
Many of the topics include pointed, canonical examples.
At the outset, it is important to recognize that C++ is a vast
language, admittedly difficult to describe in a pocket refer-
ence. As a result, this reference is devoted almost exclusively
to presenting the language itself. Other references are avail-
able from O’Reilly & Associates describing the C++ Stan-
dard Library, a vast subject on its own. The C++ Standard
Library includes all of the facilities of the C Standard Library
plus many new ones, such as the Standard Template Library
(STL) and I/O streams.
This book has been written for developers with a variety of
backgrounds and experience levels in C++. Those with expe-
rience using C++ will find this book to be a uniquely focused
reference to its most commonly used features. If you are new
to C++, you may wish to work with a tutorial first and return
to this reference later to research specific topics.
1
Typographic Conventions
This book uses the following typographic conventions:
Italic
This style is used for filenames and for items emphasized
in the text.
Constant width
This style is used for code, commands, keywords, and
names for types, variables, functions, and classes.
Constant width italic
This style is used for items that you need to replace.
Acknowledgments
I would like to thank Jonathan Gennick, my editor at
O’Reilly, for his support and direction with this book.
Thanks also to Uwe Schnitker, Danny Kalev, and Ron Passe-
rini for taking the time to read and comment on an early
draft of this book.
Compatibility with C
With some minor exceptions, C++ was developed as an
extension, or superset, of C. This means that well-written C
programs generally will compile and run as C++ programs.
(Most incompatibilities stem from the stricter type checking
that C++ provides.) So, C++ programs tend to look syntacti-
cally similar to C and use much of C’s original functionality.
This being said, don’t let the similarities between C and C++
fool you into thinking that C++ is merely a trivial derivation
of C. In fact, it is a rich language that extends C with some
grand additions. These include support for object-oriented
programming, generic programming using templates,
namespaces, inline functions, operator and function over-
loading, better facilities for memory management, refer-
ences, safer forms of casting, runtime type information,
exception handling, and an extended standard library.
Startup
The function main is the designated start of a C++ program,
which you as the developer must define. In its standard form,
this function accepts zero or two arguments supplied by the
operating system when the program starts, although many
C++ implementations allow additional parameters. Its return
type is int. For example:
int main( )
int main(int argc, char *argv[])
Program Structure | 3
#include "Account.h"
if (argc > 1)
account.deposit(atof(argv[1]));
while (true)
{
cout << "Balance is "
<< account.getBalance( )
<< endl;
switch (action)
{
case 'd':
cout << "Enter deposit: ";
cin >> amount;
account.deposit(amount);
break;
case 'w':
cout << "Enter withdrawal: ";
cin >> amount;
account.withdraw(amount);
break;
case 'q':
exit(0);
default:
cout << "Bad command" << endl;
}
}
return 0;
}
Termination
A C++ program terminates when you return from main. The
value you return is passed back to the operating system and
becomes the return value for the executable. If no return is
present in main, an implicit return of 0 takes places after fall-
ing through the body of main. You can also terminate a pro-
gram by calling the exit function (from the C++ Standard
Library), which accepts the return value for the executable as
an argument.
Header Files
Header files contain source code to be included in multiple
files. They usually have a .h extension. Anything to be
included in multiple places belongs in a header file. A header
file should never contain the following:
• Definitions for variables and static data members (see
“Declarations” for the difference between declarations
and definitions).
• Definitions for functions, except those defined as tem-
plate functions or inline functions.
• Namespaces that are unnamed.
NOTE
Header files in the C++ Standard Library do not use the .h
extension; they have no extension.
Program Structure | 5
Often you create one header file for each major class that you
define. For example, Account is defined in the header file
Account.h, shown below. Of course, header files are used for
other purposes, and not all class definitions need to be in
header files (e.g., helper classes are defined simply within the
source file in which they will be used).
#ifndef ACCOUNT_H
#define ACCOUNT_H
class Account
{
public:
Account(double b);
private:
double balance;
};
#endif
Source Files
C++ source files contain C++ source code. They usually
have a .cpp extension. During compilation, the compiler typi-
cally translates source files into object files, which often have
a .obj or .o extension. Object files are joined by the linker to
produce a final executable or library.
Often you create one source file for each major class you
implement. For example, the implementation of Account is in
Account.cpp, shown below. Of course, there is no require-
ment about this; source files often contain more than just the
implementation of a single class.
#include "Account.h"
Account::Account(double b)
{
balance = b;
}
Program Structure | 7
Preprocessor Directives
The C++ preprocessor can be used to perform a number of
useful operations controlled via several directives. Each direc-
tive begins with a pound sign (#) as the first character that is
not whitespace on a line. Directives can span multiple lines
by including a backslash (\) at the end of intermediate lines.
#define
The #define directive replaces an identifier with the text that
follows it wherever the identifier occurs in a source file. For
example:
#define BUFFER_SIZE 80
char buffer[BUFFER_SIZE];
NOTE
In C++, it is preferable to use enumerations, and to a
lesser degree, variables and data members declared using
the keywords const or static const for constant data,
rather than the #define directive.
int x = 5, y = 10, z;
#undef
The #undef directive undefines an identifier so that a check
for its definition tests false. For example:
#undef LOGGING_ENABLED
Program Structure | 9
#elif (LOGGING_LEVEL == LOGGING_MAX && \
LOGGING_FLAG)
cout << "Logging is maximum" << endl;
#elif LOGGING_FLAG
cout << "Logging is standard" << endl;
#endif
#include
The #include directive causes the preprocessor to include
another file, usually a header file. You enclose standard
header files with angle brackets, and user-defined header files
with quotes. For example:
#include <iostream>
#include "Account.h"
#error
The #error directive causes compilation to stop and a speci-
fied string to be displayed. For example:
#ifdef LOGGING_ENABLED
#error Logging should not be enabled
#endif
#line
The #line directive causes the preprocessor to change the
current line number stored internally by the compiler during
compilation in the macro _ _LINE_ _. For example:
#line 100
Preprocessor Macros
The C++ preprocessor defines several macros for insert-
ing information into a source file during compilation.
Each macro begins and ends with two underscores, except
for _ _cplusplus, which has no terminating underscores.
_ _LINE_ _
Expands to the current line number of the source file
being compiled.
_ _FILE_ _
Expands to the name of the source file being compiled.
_ _DATE_ _
Expands to the date on which the compilation is taking
place.
_ _TIME_ _
Expands to the time at which the compilation is taking
place.
_ _TIMESTAMP_ _
Expands to the date and time at which the compilation is
taking place.
Program Structure | 11
_ _STDC_ _
Will be defined if the compiler is in full compliance with
the ANSI C standard.
_ _cplusplus
Will be defined if the program being compiled is a C++
program. How a compiler determines whether a given
program is a C++ program is compiler-specific. You may
need to set a compiler option, or your compiler may look
at the source file’s extension.
Fundamental Types
The type for an identifier determines what you are allowed to
do with it. You associate a type with an identifier when you
declare it. When declaring an identifier, you also may have
the opportunity to specify a storage class and one or more
qualifiers (see “Declarations”).
The fundamental types of C++ are its Boolean, character,
integer, floating-point, and void types. The Boolean, charac-
ter, and integer types of C++ are called integral types. Inte-
gral and floating-point types are collectively called arithmetic
types.
bool
Booleans are of type bool. The bool type is used for values of
truth. For example:
bool flag;
...
if (flag)
{
// Do something when the flag is true.
}
Boolean values
Booleans have only two possible values: true or false. The
typical size of a bool is one byte.
Character values
The range of values that characters may represent is found in
the standard header file <climits>. The size of a char is one
byte. The size of a byte technically is implementation-
defined, but it is rarely anything but eight bits. The size of
Fundamental Types | 13
the wchar_t type is also implementation-defined, but is typi-
cally two bytes.
Character literals
Character literals are enclosed by single quotes. For example:
char c = 'A';
Integer values
The range of values that each of the integer types may repre-
sent is found in the standard header file <climits>. The exact
size of a short, int, or long is left up to the compiler, but is
typically two, four, or four bytes respectively. Although the
size of each type can vary, the compiler guarantees that the
size of a short is less than or equal to the size of an int, and
the size of an int is less than or equal to the size of a long.
Integer literals
Literals for integers have several forms, as shown in Table 2.
If U, u, L, or l is not used as a suffix, the compiler assigns a
type appropriate for the magnitude of the literal.
Fundamental Types | 15
Table 2. Integer literals
Examples Description
12 The most common form of integer literals.
-5
012 Literals that begin with 0 are octal values (e.g., 012 is the octal literal
0377 for the decimal number 10).
0x2a Literals that begin with 0x are hexadecimal values (e.g., 0x2a is the
0xffff hexadecimal literal for the decimal number 42).
256L Literals with L (or l) in the suffix are treated as long.
0x7fL
0x80U Literals with U (or u) in the suffix are treated as unsigned.
0xffffUL
Floating-point values
The range and precision of values that each of the floating-
point types may represent is found in the standard header file
<cfloat>. The exact size, range, and precision of a float,
double, or long double is left up to the compiler, but is typi-
cally four, eight, or ten bytes respectively. Although the size
of each type can vary, the compiler guarantees that the size of
a float is less than or equal to the size of a double, and the
size of a double is less than or equal to the size of a long
double.
Floating-point literals
Literals for floating points can take on several forms, as
shown in Table 3. If F, f, L, or l is not used as a suffix, the
compiler assigns a type of double.
void
The void type indicates the absence of a value. One use is in
declaring functions that do not return a value. For example:
void sayHello( )
{
cout << "Hello" << endl;
}
Compound Types
Arithmetic types are the building blocks for more complex
types, called compound types. These include enumerations,
arrays, strings, pointers, pointers to members, references,
and the various class types of C++, as well as functions.
Arithmetic types, enumerations, pointers, and pointers to
members are collectively called scalar types.
Compound Types | 17
Enumerations
An enumeration, specified by the keyword enum, is a set of
integer constants associated with identifiers, called
enumerators, that you define. In general, enumerations pro-
vide a way to use meaningful names where you might other-
wise use integer constants, perhaps defined using the
preprocessor directive #define. Enumerations are preferred
over the preprocessor for this in C++ because they obey the
language’s rules of scope. The following defines an enumera-
tion for the colors of the rainbow:
enum SpectrumColor
{
Red, Orange, Yellow,
Green, Blue, Indigo,
Violet
};
ASCII_A = 65, // 65
ASCII_B, // 66
BufferSize = 8 // 8
};
char buffer[BufferSize];
Arrays
Arrays contain a specific number of elements of a particular
type. So that the compiler can reserve the required amount of
space when the program is compiled, you must specify the
type and number of elements that the array will contain
when it is defined. The compiler must be able to determine
this value when the program is compiled. For example:
enum
{
HandleCount = 100
};
int handles[HandleCount];
Once an array has been defined, you use the identifier for the
array along with an index to access specific elements within
Compound Types | 19
the array. The following sets each element in the previous
array to an initial value of –1:
for (int i = 0; i < HandleCount; i++)
{
handles[i] = -1;
}
Multidimensional arrays
C++ supports multidimensional arrays, which are arrays
defined using more than one index, as follows:
enum
{
Size1 = 4,
Size2 = 4
};
double matrix[Size1][Size2];
Compound Types | 21
enum SwitchState
{
On, Off
};
SwitchState switches[] =
{
On, Off, On, Off
};
Strings
Character (C-style) strings are arrays of characters termi-
nated with a null character (\0). The characters of the string
are of type char, or type wchar_t for wide-character strings.
For example:
enum
{
NameLength = 81
};
You must allocate one extra character for the null terminator
in arrays of characters to be used for strings. Functions that
return a string’s length, such as strlen (from the C++ Stan-
dard Library), do not include a string’s null terminator in the
length returned. Wide-character versions of standard facili-
ties typically have the prefix w or use wcs instead of str (e.g.,
wostream, wcsncpy, etc.).
NOTE
Although many facilities in the C++ Standard Library
work with character (C-style) strings, the preferred way
to work with strings in C++ is to use the string class
from the C++ Standard Library. The wide-character ver-
sion is wstring.
String literals
String literals are enclosed in double quotes. For example:
char name[] = "Margot";
Compound Types | 23
Pointers
For any type T, there is a corresponding type pointer to T for
variables that contain addresses in memory of where data of
type T resides. T is the base type of a pointer to T. Pointers
are declared by placing an asterisk (*) before the variable
name in a declaration (see “Declaring Variables”). In the fol-
lowing example, i is an int while *iptr is a pointer to i:
int i = 20;
int *iptr = &i;
Pointer dereferencing
Dereferencing a pointer yields what the pointer points to. To
dereference a pointer, you precede it with an asterisk in an
expression, as shown in the commented lines below:
int i = 20;
int *iptr = &i;
int j;
int k = 50;
Pointer arithmetic
Pointers in expressions are evaluated using the rules of
pointer arithmetic. When an operator for addition, subtrac-
tion, increment, or decrement is applied to a pointer p of
type T, p is treated as an array of type T. As a result, p + n
Void pointers
Pointers of type void are permitted to point to data of any
type. For example:
Circle c(2.0);
void *p;
p = &c; // c is a circle.
c = static_cast<Circle *>(p);
Null pointers
Pointers of any type can be assigned the value 0, which indi-
cates that the pointer points to nothing at all. A pointer with
the value 0 is called a null pointer. You should never derefer-
ence a null pointer.
Function pointers
A function pointer is a pointer that points to a function. Its
type is related to the signature of the function to which it
Compound Types | 25
points. For example, the following defines a function named
addOne, then defines inc as a pointer to a function that takes
a reference to an int as a parameter and returns void. inc is
then set to addOne, which has that same signature:
void addOne(int &x)
{
x += 1;
}
The last line could also be written as shown below (using the
address-of operator, &, before addOne):
void (*inc)(int &x) = &addOne;
The last line could also be written as shown below (using the
indirection operator, *, before the pointer):
(*inc)(a);
Pointers to Members
Pointers to members are like alternative names for class
members (see “Classes, Structs, and Unions”). For example,
assume that class X has a member of type int called data:
int X::*p = &X::data;
X object;
X *objptr = new X;
int i = object.*p;
int j = objptr->*p;
References
References are used to provide alternative names for vari-
ables. They are declared by placing an ampersand (&) before
the variable name in a declaration. For example:
int i = 20;
int &r = i;
Reference parameters
A common use of references is with parameters for func-
tions. References allow changes to parameters to be reflected
in the caller’s environment. For example:
Compound Types | 27
void xchg(int &x, int &y)
{
int t = x;
x = y;
y = t;
}
References as l-values
References are also often used in C++ as return values for
functions. This allows the return value of a function to be
used as an l-value, which is a value that can appear on the
left side of an assignment.
Class Types
The class types of C++ are classes, structs, and unions (see
“Classes, Structs, and Unions”).
Type Conversions
Type conversions are performed when you use a cast explic-
itly (see “Casts and Runtime Type Information”), and at
times implicitly by the compiler. For example, the compiler
Implicit conversions
Implicit conversions occur between C++’s arithmetic types,
between certain pointer types (see “Pointers”), and between
user-defined types and others. The implicit conversion of
arithmetic types and pointer types in binary operations is car-
ried out by converting the smaller or less precise type to the
larger or more precise one. Booleans, characters, and inte-
gers smaller than an int are first converted to an int using
integral promotion. When an integer and a floating point
appear in the same operation, the integer is converted to the
floating-point type.
Preservation of values
The implicit conversion of arithmetic types is performed in
such a way as to preserve the original values of the entities
being converted whenever possible. However, there are many
situations in which surprising results can occur. For exam-
ple, a compiler may not warn about conversions from wider
or more precise types to smaller or less precise ones (e.g.,
from long to short, or double to float), in which a wider
value may not be representable in the smaller type. In addi-
tion, the conversion from an unsigned type to a signed one
can result in a loss of information.
User-defined conversions
You can specify explicit conversions for user-defined types by
defining user-defined conversion operators (see “Overload-
ing Operators”). For example, the following user-defined
conversion operator, operator double, converts an Account
object to a double:
class Account
{
public:
operator double( )
{
return balance;
}
...
private:
double balance;
};
Converting constructors
A constructor that has a single parameter and is not declared
using explicit can be used by the compiler to perform
implicit conversions between the type of the parameter and
the class type. For example:
class Account
{
public:
Account(double b)
{
balance = b;
}
...
private:
double balance;
};
uint32 value32bit;
IntStringMap m;
Lexical Elements
At the most fundamental level, a C++ program consists of
individual lexical elements called tokens. Tokens are delin-
eated by whitespace (spaces, newlines, tabs, etc.), or can be
formed once the start of another token is recognized, as
shown below:
ival+3
Lexical Elements | 31
Tokens are passed to the parser, which determines if a
stream of tokens has the correct syntax. Tokens together
form more complex semantic constructs, such as declara-
tions, expressions, and statements that affect the flow of
execution.
Comments
Comments are notes written in the source code for develop-
ers; they are ignored completely by the compiler. The prepro-
cessor converts each comment to a single space before the
compiler ever gets the chance to see it.
A comment is any block of text enclosed between /* and */,
or following // on a single line. Comments of the first form
cannot be nested within one another. They usually span mul-
tiple lines. For example:
/* This comment has more than one line.
Here is another part of the comment.*/
Identifiers
Identifiers in C++ are sequences of characters that are used
for names of variables, functions, parameters, types, labels,
namespaces, and preprocessor macros. Identifiers may con-
sist of letters, digits, and underscores, but they must not
begin with a digit. For example, the following are all legal
C++ identifiers:
i addressBook Mgr item_count
ptr2 NAME_LENGTH class_ showWindow
NOTE
There is no one stylistic convention for identifiers upon
which everyone agrees. One common convention, howev-
er, is to use lowercase characters to begin names for local
variables, data members, and functions. Uppercase char-
acters are then used to begin the names of types,
namespaces, and global variables. Names processed by
the preprocessor are written entirely in uppercase. Names
of parameters in macros are written entirely in lowercase.
Reserved Words
C++ defines a number of keywords and alternative tokens,
which are sequences of characters that have special meaning
in the language. These are reserved words and cannot be
used for identifiers. The reserved words of C++ are listed
below:
and and_eq asm
auto bitand bitor
bool break case
catch char class
compl const const_cast
continue default delete
do double dynamic_cast
else enum explicit
export extern false
float for friend
goto if inline
Lexical Elements | 33
int long mutable
namespace new not
not_eq operator or
or_eq private protected
public register reinterpret_cast
return short signed
sizeof static static_cast
struct switch template
this throw true
try typedef typeid
typename union unsigned
using virtual void
volatile wchar_t while
xor xor_eq
Literals
Literals are lexical elements that represent explicit values in a
program. C++ defines many types of literals. Each is
described under its respective type in “Fundamental Types.”
Operators
An operator is used to perform a specific operation on a set
of operands in an expression. Operators in C++ work with
anywhere from one to three operands, depending on the
operator.
Associativity
Operators may associate to the left or right. For example,
assignment operators (=, +=, <<=, etc.) associate to the right.
Therefore, the following:
i = j = k
actually implies:
i = (j = k)
Precedence
Operators also have an order, or precedence, by which
expressions that contain them are evaluated. Expressions
containing operators with a higher precedence are evaluated
before those containing operators with a lower precedence.
You can use parentheses around an expression to force
grouping. Even when not essential, it’s best to use parenthe-
ses in expressions to document your intentions. The number
of operators in C++ often makes their precedence difficult to
remember.
Table 4 lists the operators of C++ from highest precedence
to lowest and describes how each operator associates. Each
section contains operators of equal precedence. The table
also describes the behavior of each operator when used with
the intrinsic types of C++. For most operators, C++ lets you
define additional behaviors for your own types (see “Over-
loading Operators”).
Table 4. Operators
Operator Description Associates
:: Scope resolution No
[] Array subscript Left
. Member selection Left
-> Member selection Left
() Function call Left
() Value construction No
++ Postfix increment No
-- Postfix decrement No
typeid Type information No
*_cast C++ cast No
Lexical Elements | 35
Table 4. Operators (continued)
Operator Description Associates
sizeof Size information No
++ Prefix increment No
-- Prefix decrement No
~ Bitwise NOT No
! Logical NOT No
- Unary minus No
+ Unary plus No
& Address-of No
* Indirection No
new Allocate No
new[] Allocate No
delete Deallocate No
delete[] Deallocate No
() C-style cast Right
.* Pointer-to-member selection Left
->* Pointer-to-member selection Left
* Multiply Left
/ Divide Left
% Modulo (remainder) Left
+ Add Left
- Subtract Left
<< Shift left Left
>> Shift right Left
< Less than Left
<= Less than or equal to Left
> Greater than Left
>= Greater than or equal to Left
== Equal to Left
!= Not equal to Left
Lexical Elements | 37
The scope operator can also be used without a scope name to
specify file (global) scope. For example:
::serialize(i);
Array subscript ([ ])
The array subscript operator is used to access individual ele-
ments of arrays or memory referenced by pointers. For exam-
ple:
tmp = table[0];
if (i++ == 0)
{
// This is the first time called.
}
}
typeid
The typeid operator gets runtime type information for an
operand. See “Casts and Runtime Type Information” for a
complete description of this operator.
C++ cast
Type cast operators specific to C++ are dynamic_cast,
static_cast, const_cast, and reinterpret_cast. See “Casts
and Runtime Type Information” for a complete description
of these operators.
Lexical Elements | 39
sizeof
The sizeof operator gets the size of its operand. For example:
size_t s = sizeof(c);
if (++i == 1)
{
// This is the first time called.
}
}
while (!done)
{
// Set done to true when finished.
}
Address-of (&)
The address-of operator gets the address at which its oper-
and resides in memory. For example:
Circle c;
Circle *p = &c;
Indirection (*)
The indirection operator dereferences a pointer and gets the
value that it addresses. For example:
int i;
int *p = new int;
*p = 5;
i = *p;
This assigns the value 5 to i. The type of the result is the type
from which the pointer is derived. The operand must be a
pointer.
Lexical Elements | 41
Allocate and deallocate
The C++ memory management operators are new, new[],
delete, and delete[]. They allocate and reclaim memory on
the heap. See “Memory Management” for a complete
description of these operators.
int i = object.*p;
int j = objptr->*p;
Arithmetic (*, /, %, +, –)
Arithmetic operators perform multiplication (*), division (/),
modulus (%), addition (+), and subtraction (–) using two
operands. For example:
if (x % 2 == 0)
{
// The integer x is an even number.
}
This assigns 0x4 back into bits. The first operand is the one
shifted; the second is the number of bits to shift. Both oper-
ands must be one of the Boolean, character, or integer types
of C++. These operators are commonly used for insertion
and extraction with I/O streams as well (see “I/O Streams”).
Lexical Elements | 43
For the bitwise XOR operator, if one bit is 0 and the other is
1, the corresponding result bit is 1; otherwise, the bit is 0.
For example, the following sets a to 0xA0:
unsigned char a, b = 0xaa, c = 0x0a;
a = b ^ c;
Lexical Elements | 45
a = b = c;
Exception (throw)
The throw operator is used to throw an exception. See
“Exception Handling” for a complete description of this
operator.
Sequence (,)
The sequence operator, which is a comma, evaluates two
operands from left to right. The value of the expression
becomes the value of the last operand. For example:
for (i = 0, j = 10; i < 10; i++, j--)
{
// Increase i while making j smaller.
}
Expressions
An expression is something that yields a value. Nearly every
type of statement uses an expression in some way. For exam-
ple, the declaration below uses an expression for its initial-
izer:
int t = (100 + 50) / 2;
Local Scope
A name has local scope when it is declared inside of a block.
A block is a compound statement that begins with a left
brace ({) and ends with a right brace (}). For example:
void f( )
{
int i = 10;
...
}
Class Scope
A name has class scope when it is declared within the con-
fines of a class and does not have local scope. For example:
class Event
{
public:
enum Type
{
keyDown,
...
};
...
Type getType( ) const
{
return type;
}
...
private:
Scope | 47
Type type;
...
};
Here, Type, keyDown, getType, and type all have class scope. A
name with class scope is visible inside of the class in which it
is declared, and outside of the class using a selection or scope
operator, depending on what the name represents. To use a
name with class scope outside of its declaring class, the
access level for the name must also allow access to it (see
“Access Levels for Members”).
NOTE
A name declared within a block that is within a class has
a scope local to that block, and does not have class scope.
Namespace Scope
A name declared inside of a namespace has namespace scope
(see “Namespaces”). For example:
namespace Aviation
{
const double NMPerSM = 0.826201;
}
File Scope
A name that is not declared in a block, class, or namespace
has file scope. A name with file scope can be used anywhere
within a file after the point where the name is declared. A
name for a variable, object, or function with file scope that
has not been declared using the keyword static is called a
Other Scopes
Labels (see “Jump Statements”) and the parameters in proto-
types have their own scopes. The scope of a label is the func-
tion in which the label is used, even if the label is defined
inside of a block. This allows jumping into or out of a block.
The scope of a prototype parameter goes to the end of the
prototype; however, a parameter cannot be used to define
default values for other parameters.
Enclosing Scopes
A name is visible in any scope that its declaring scope
encloses. For example:
const double NMPerSM = 0.826201;
return nm * NMPerSM;
}
Scope | 49
NOTE
In general, hiding names leads to errors that are difficult
to discover. Therefore, this sort of thing should be avoid-
ed as much as possible.
Declarations
A name must be declared within the necessary scope before it
can be used. A declaration is often a definition as well. A
name may be declared in multiple places throughout a pro-
gram; however, it must be defined only once. If multiple dec-
larations for a name exist, all must be identical.
The declaration of a function is a definition when you pro-
vide a body for the function; the declaration of a variable is a
definition whenever storage is allocated. In short, a declara-
tion is a definition except in the following situations:
• A variable is declared using the keyword extern (see
“Storage Classes”), and no initializer is provided.
• The declaration is for a static data member; static data
members are defined outside of their class.
• The declaration introduces a class name with no defini-
tion, in other words a forward declaration.
• The declaration is a prototype for a function; prototypes
have no body.
• The declaration is a typedef statement, which declares a
synonym for an existing type.
Pointer variables
Declarations for pointers follow the same rules as for other
types of variables, except you must be sure to precede each
name with an asterisk (*). For example:
int *p, *q, *r;
Declarations | 51
Initialization
Optionally, you can initialize variables using an initializer
where they are defined. Variables declared using the key-
word const must be initialized. When an initializer appears,
it must evaluate to the correct type. For example:
bool done = false;
static const int max = 100;
int timers[] = {5, 5, 5};
int *p, *q = 0, *r;
Declaring Functions
At their simplest, declarations for functions consist of the fol-
lowing: a return type, a name, and a comma-delimited list of
zero or more parameters enclosed by parentheses. Names are
not required for parameters, but they serve as good docu-
mentation. For example:
void xchg(int &x, int &y);
Default arguments
Default arguments can be specified for the parameters of
functions. You do this by setting a parameter equal to its
default value in the function declaration, as shown below:
void isTempOK(const int t,
const int low = 20,
const int high = 50);
Declarations | 53
there is no way to provide an argument for a parameter after
any that have assumed default values. So, for example, the
following invocation passes 30 to low:
if (!isTempOK(temp, 30))
{
// Do something if too low or high.
}
Inline functions
An inline function is a function whose body is substituted
directly at every point in a program where the function is
called, as opposed to generating a call using the stack and a
single copy of the function. To make a function inline, you
precede its definition with the keyword inline, as follows:
inline void xchg(int &x, int &y)
{
int t = x;
x = y;
y = t;
}
NOTE
The inline keyword is just a request to the compiler to
inline a function. The compiler makes the ultimate
decision.
static
The following list summarizes the meanings of the storage
class static in various contexts:
Local variables
Persist between executions of their enclosing block. They
are constructed only once, or never if their declaration is
never reached.
Global variables
Have file scope. Unnamed namespaces are a better way
to achieve this.
Data members
A single instance of a static data member is shared by all
instances of its class. Static data members are initialized
before main is called.
Declarations | 55
Nonmember functions
Have file scope. Unnamed namespaces offer a better way
to achieve this.
Member functions
Can be called without an instance of their class, but can-
not themselves access members of their class that are not
also declared static.
extern
When applied to a global variable or to a nonmember func-
tion, the extern storage class specifies that the variable or
function is defined in another source file. Nonmember func-
tions have the storage class extern by default.
mutable
The mutable storage class can be applied only to a class data
member. It specifies that the member can be modified even
though its containing object has been declared using the key-
word const.
auto
The auto storage class instructs the compiler to allocate stor-
age automatically for a variable on the stack each time a
block is entered. Local variables are automatic by default;
therefore, auto is rarely used.
register
The register storage class requests that the address of a vari-
able be stored in a machine register for better performance.
The register storage class is only a request; the compiler
decides whether or not to use a register.
const
The const qualifier keeps the entity it qualifies from being
modified, except for data members declared using keyword
mutable (see “Storage Classes”). The following rules apply:
Local variables
Once initialized, cannot be modified. They must be ini-
tialized.
Global variables
Once initialized, cannot be modified. They must be ini-
tialized.
Data members
Once initialized, cannot be modified. They must be ini-
tialized when an object is constructed.
Nonstatic member functions (where const appears at the end
of the signature)
Cannot modify nonstatic data members of their class
except those declared using mutable. The member func-
tions are allowed to be invoked through const instances
of their class.
Function parameter
Cannot be changed by the function.
Return value of a function
Can be used only where a const value is permitted.
Pointer declarations use a syntax with const that depends on
what you want to protect from modification. If you want to
protect what a pointer addresses from being modified, you
use a declaration like the following:
int i = 100, j = 200;
const int *p = &i;
Declarations | 57
*p = j; // This is an error.
p = &j; // This is OK.
*p = j; // This is OK.
p = &j; // This is an error.
In the event that you want to protect both the data and the
pointer from being modified, you use a declaration that is a
combination of the two presented previously, as in this
example:
int i = 100, j = 200;
const int *const p = &i;
volatile
The volatile qualifier informs the compiler that a variable,
data member, or parameter may be modified unexpectedly,
be it by another process, the hardware, or something else.
As a result, the compiler avoids optimizations that could
conflict with changes happening asynchronously to the
entity (e.g., normally a compiler will skip accessing memory
again if it needs a value that was just obtained in the previ-
ous instruction).
When applied to member functions, volatile has a slightly
different shade of meaning. When you create a volatile object
of a class, the compiler will only allow you to call member
functions that have also been declared volatile. Thus, you
should apply the volatile qualifier to member functions in
cases when you expect to create volatile objects of a class,
and even then only apply volatile to those functions you
intend to invoke on those volatile objects.
Expression Statements
An expression statement is an expression followed by a single
semicolon (;). Expression statements cause an expression to
be evaluated. Side effects, such as an assignment to a vari-
able, are completed before the next statement is executed.
For example:
a = 10;
Null Statements
A null statement is written as a semicolon (;). Null state-
ments are useful when the syntax of C++ requires a state-
ment but you don’t need anything performed. For example:
void spin(int n)
{
for (int i = 0; i < n; i++)
;
}
Compound Statements
A compound statement is a group of zero or more statements
beginning with a left brace ({) and ending with a right brace
(}). For example:
while (true)
{
// Start of a compound statement.
...
Statements | 59
if (!done)
{
// Another compound statement.
}
else
{
// Another compound statement.
}
}
Iteration Statements
Iteration statements cause a statement or block to be exe-
cuted repeatedly. There are three types of iteration state-
ments in C++: while, do, and for.
while
A while loop repeats a statement or block as long as an
expression (which can be a declaration) evaluated at the top
of the loop is true. For example:
char ch = 'y';
do
A do loop repeats a statement or block as long as an expres-
sion evaluated at the bottom of the loop is true. For example:
do
{
// Do something to be repeated.
...
for
A for loop is similar to a while loop, but additional mecha-
nisms are provided for initializing the loop and making
adjustments after each of its iterations. For example:
// Prevent warnings in Visual C++.
#pragma warning(disable:4786)
IntStringMap m;
char s[4];
m.insert(IntStringMap::value_type(i,
string(s)));
}
Statements | 61
loop terminates. After each iteration, the rightmost expres-
sion is evaluated, and the cycle is repeated. for loops can con-
tain more complicated expressions as well. For example:
void upperString(char *t, const char *s)
{
for (; *s != '\0'; *(t++) = toupper(*(s++)))
;
*(t++) = '\0';
}
NOTE
A name declared in a for initialization statement is visi-
ble until the end of the for loop.
Selection Statements
Selection statements execute a different statement or block
based on the result produced by an expression. There are
two types of selection statements in C++: if and switch.
if
An if statement evaluates an expression (which may be a
declaration) and uses the result to determine which of up to
two statements or blocks to execute next. For example:
if (i > 0 && i < 100)
{
// Do something when within range.
}
else
{
// Do something when not in range.
}
switch
A switch statement selects one of several sections of code to
execute based on the value of a controlling expression. For
example:
switch (type)
{
case keyDown:
// Do something for a key down.
...
break;
case keyUp:
// Do something for a key up.
...
break;
...
default:
// Handle anything not handled.
...
}
Statements | 63
Jump Statements
Jump statements jump unconditionally to a different state-
ment. There are four types of jump statements in C++:
break, continue, goto, and return.
break
A break statement is used to jump out of an innermost loop
or switch statement. For example:
for (;;)
{
if (done)
break;
continue
A continue statement is used to jump to the start of an inner-
most enclosing loop. For example:
while (!done)
{
// If we need to skip the end portion
// of the function, set skip to true.
...
if (skip)
continue;
goto
A goto statement jumps to a label that you specify. For exam-
ple:
if (GetLastError( ) != ERROR_SUCCESS)
goto handleError;
handleError:
// Do something to handle error state.
return
A return statement jumps out of a function, and if needed
sets a return value. For example:
double convertToSM(double nm)
{
return nm * NMPerSM;
}
Statements | 65
Namespaces
A namespace defines a named scope. Namespaces are used
to group related names and to avoid clashes between similar
names in different parts of large programs. You declare a
namespace as follows:
namespace Aviation
{
const double NMPerSM = 0.826201;
using Declarations
A using declaration lets you use a name from a namespace
without having to qualify it. For example:
namespace Aviation
{
double convertToSM(double nm);
double convertToNM(double sm);
}
...
using Aviation::convertToSM;
...
double sm = convertToSM(20.0);
using Directives
A using directive lets you use all names from a namespace
without qualifying them. For example:
namespace Aviation
{
double convertToSM(double nm);
double convertToNM(double sm);
}
...
using namespace Aviation;
...
Namespaces | 67
double sm = convertToSM(20.0);
double nm = convertToNM(40.0);
Unnamed Namespaces
A namespace is unnamed when you omit the name for it in
its declaration. For example:
namespace
{
...
}
private:
double balance;
};
Declaring Objects
Objects are specific instances of a class. The following
declares an object that is an instance of Account:
Account account(100.0);
Accessing Members
To access a member of an object, you use the dot form of the
selection operator (.). For example, the following assigns 500
to the data member i of an object called object:
object.i = 500;
You qualify a static data member outside of its class with the
name of the class using the scope operator (::). You can refer
to a static data member without an instantiation of the class.
The access level for a static data member does not apply when
defining the member (see “Access Levels for Members”).
NOTE
Definitions of member functions outside of their class be-
long in the source file for the class, not in the class’s
header file (see “Header Files”). Otherwise, the member
function ends up being defined more than once when the
header file is included multiple times. The exceptions to
this are definitions of member functions preceded by the
keyword inline, and those implementing template class-
es; these go in header files.
implies:
class Account
{
public:
...
void deposit(double amt)
{
this->balance += amt;
}
...
private:
double balance;
};
private:
double balance;
};
Friends
Friends of classes are granted access to all members of the
class. You can declare functions (including member func-
tions of other classes) or entire classes as friends of a class.
For example:
class Account
{
friend class AccountManager;
public:
Account(double b);
private:
double balance;
};
Constructors
Constructors are special member functions used to initialize
instances of a class. They give you the opportunity to per-
form initialization (e.g., allocating dynamic storage for data
members, opening files, etc.) before an object is ever used.
Constructors are called whenever storage is allocated for an
object, whether automatically by the compiler or when you
use new or new[] (see “Memory Management”). See “Con-
structors and Inheritance” for information about construc-
tors and base classes.
Constructors have the same name as the class and never
return a value. For example:
class Account
{
public:
Account(double b);
...
};
Default constructors
Default constructors are constructors that take no argu-
ments or that have default values specified for all arguments.
To instantiate an object using its default constructor, use one
of the following approaches:
Account account;
Account *p = new Account;
Copy constructors
Copy constructors are special constructors that accept a ref-
erence to an instance of their own class (usually a const
instance). For example:
class Account
{
public:
Account(const Account &a);
...
};
Explicit constructors
Constructors declared as explicit do not take part in implicit
conversions (see “Type Conversions”). You use the keyword
explicit to declare a constructor as explicit. For example:
class Account
{
public:
explicit Account(double b)
{
balance = b;
}
...
private:
double balance;
};
Member initializers
Member initializers stipulate how to initialize data members
even before the constructor is executed. Member initializers
Destructors
Destructors are special member functions invoked when an
instance of a class is about to be destroyed. They give you the
opportunity to clean up (e.g., reclaim dynamic storage used
by data members, close files, etc.) before an object goes
enum
{
LargePIN = 8,
SmallPIN = 4
};
...
void setStatus(Status s);
void setMinPIN(int n);
...
};
p->setMinPIN(Account::LargePIN);
p->setStatus(Account::Status::Valued);
This informs the compiler that you plan to define the class
later but are going to use its name now without referring to
any of the class’s members. For example, forward declara-
tions are needed when two classes refer to each other:
class Account;
class Bank
{
...
private:
Account *accounts;
};
class Account
{
...
private:
Bank *bank;
};
Structs
Structs are functionally identical to classes except that the
default access level for their members is public, not private.
To define a struct, you use the keyword struct in place of the
keyword class.
Unions
Unions are similar to classes; however, they can hold a value
for only one data member at a time. As a result, a union
int type;
union
{
char name[20];
double balance;
};
};
When setting a value in the union, you record how the union
is being used. For example:
AccountInfo info;
info.type = AccountInfo::BalanceInfo;
info.balance = 100.0;
Inheritance
When you derive one class from another, the derived class
inherits the data members and member functions that the
other class defines (subject to access controls) while adding
its own. Aside from the benefits that inheritance offers stem-
ming from the reuse of functionality provided by the base
class, inheritance is fundamental to supporting polymor-
phism (see “Virtual Member Functions”), an essential part of
object-oriented programming. Consider the version of
Account below:
class Account
{
public:
Account(double b);
protected:
double balance;
};
void addInterest( );
void chargeFee(double c);
bankAccount.deposit(50.0);
bankAccount.addInterest( );
Order of construction
The constructor for each class in the derivation chain is
called beginning with the base class at the top of the deriva-
tion chain and ending with the most derived class.
Inheritance | 89
Account(0.0),
interestRate(r)
{
}
...
private:
double interestRate;
};
Order of destruction
The destructor for each class in the derivation chain is called
beginning with the most derived class and ending with the
base class at the top of the derivation chain.
Virtual destructors
When deleting an object using a base class pointer or refer-
ence, it is essential that destructors for each of the classes in
the derivation chain get the chance to run:
BankAccount *bptr;
Account *aptr;
NOTE
Not declaring a destructor using the keyword virtual in a
class from which other classes are later derived is a com-
mon source of memory leaks and other unexpected be-
havior. This is because only the destructor of the
pointer’s class is called; no polymorphic behavior occurs.
Inheritance | 91
{
balance -= amt;
}
protected:
double balance;
};
aptr->withdraw(50.0);
Inheritance | 93
morphism is made at runtime, it is possible that a member
function of a derived class with a less restrictive access level
in the base class could be invoked from a point that seem-
ingly defies its access level.
Multiple Inheritance
To derive a class from several base classes at once, you specify
the name of each class in a comma-delimited list that begins
with a colon (:) after the name of the derived class. You pre-
cede each class in the list with an access level for inheritance
(see “Access Levels for Inheritance”). For example, the
CheckingAccount class below uses multiple inheritance:
class Account
{
public:
Inheritance | 95
...
double getBalance( ) const
{
return balance;
}
...
protected:
double balance;
};
Inheritance | 97
Instances of CheckingAccount get a single balance data mem-
ber and a single getBalance method. As a result, the invoca-
tion of getBalance presented under “Multiple Inheritance” is
no longer ambiguous.
Templates
Templates are blueprints from which versions of a class or
function are generated automatically by the compiler based
on a set of parameters. Each time you use a template with a
different set of parameters, a new version of the class or func-
tion is generated to suit how you are trying to use it. Each
new version of the class or function is called a specialization
of the template.
Template Classes
To parameterize a template class, you precede its definition
with the keyword template. Template parameters, which can
be type or nontype parameters, are placed in a comma-delim-
ited list enclosed by angle brackets. Type parameters are pre-
ceded by the keyword class or typename. You use type
parameters in place of specific types within the class defini-
tion. For example:
template <class Type>
class Array
{
public:
...
bool insert(const Type
&element, int pos);
...
private:
Type *bufferForElements;
};
Templates | 99
...
}
Template Functions
To parameterize a template function, you precede its defini-
tion with the keyword template. Template parameters, which
can be type or nontype parameters, are placed in a comma-
delimited list enclosed by angle brackets. Type parameters
are preceded by the keyword class or typename. You use type
parameters in place of specific types within the function defi-
nition. For example:
template <class Type>
void xchg(Type &x, Type &y)
{
Templates | 101
Type t = x;
x = y;
y = t;
};
xchg(i, j);
xchg(a, b);
xchg<string>(s1, s2);
Templates | 103
Overloading
Overloading allows you to provide more than one definition
for a function within the same scope. It also lets you define
additional behaviors for most operators.
Overloading Functions
To overload a function, you give it several definitions, each
uniquely identifiable by the arguments it accepts; return type
is not considered. The compiler decides the definition to use
based on the arguments provided when the function is
called. For example:
char *min(char *s, char *t)
{
return (strcmp(s, t) < 0) ? s : t;
}
The first definition is used when min is called with two char-
acter pointers. The second is used when min is called with
two floating-point values. For example, you could call min in
either of the ways below:
char *s = min("abc", "xyz");
float f = min(4.56F, 1.23F);
Overloading Operators
The operators of C++ have defined behaviors with certain
intrinsic types. These behaviors cannot be changed. How-
ever, you can define additional behaviors for types of your
own. For example, one common practice is to define the <<
operator so that it can be used with cout to display objects of
your own class types (see “I/O Streams”).
You overload an operator by defining a function called
operatorX, where X is the operator you want to overload. The
number of arguments for the function depends on the num-
ber of operands an operator requires, and whether you are
overloading the operator using a member function or a func-
tion that is not a member of a class.
When you overload an operator using a member function,
the member function must be nonstatic. The invoking object
is the first operand. If the operator requires a second oper-
and, it is passed as an argument to the member function. For
example, the following class overloads += in two ways.
Overloading | 105
class Account
{
public:
Account(double b)
{
balance = b;
}
Account &operator+=(double b)
{
balance += b;
return *this;
}
Account &operator+=(const
Account &a)
{
balance += a.balance;
return *this;
}
...
private:
double balance;
}
Assignment operator
Generally, you overload the assignment operator (=) for a
class when you define a copy constructor. The assignment
operator can be overloaded using a member function only. If
you do not overload the assignment operator for a class,
member-by-member assignment is performed by default. The
function that overloads the assignment operator for a class is
not inherited by derived classes.
Overloading | 107
NOTE
For polymorphic classes, which are those containing at
least one virtual member function, it is common to de-
clare a member function called clone rather than using
the assignment operator to copy objects. Derived classes
override clone as needed.
Memory Management
C++ provides intrinsic support for allocating and reclaiming
memory dynamically as a program runs. Dynamic memory is
memory that you allocate and reclaim (i.e., manage) your-
self, as opposed to storage that is managed automatically by
the compiler on the stack, for example.
Memory Allocation
The operators used to dynamically allocate memory are new
and new[].
new
To dynamically allocate storage for a single instance of a
type, you use the new operator. For example:
int *i = new int;
double *x = new double(10.0);
new[ ]
To dynamically allocate storage for an array, you use the
new[] operator. For example:
double *da = new double[5];
Circle *ca = new Circle[8];
The class for the objects being allocated must have a default
constructor. This constructor is called for each object.
Placement new
Placement new is used to pass additional arguments to a func-
tion that overloads new or new[]. You can specify any num-
ber of arguments that an operator function you have written
accepts (see “Overloading Operators”). For example:
Account *a = new(3, x) Account;
Failed allocation
If an allocation fails, new and new[] throw a bad_alloc excep-
tion. You can use the placement version of new if you prefer a
null pointer on a failure:
char *c = new(nothrow) char[10];
You can install your own handler for dealing with failed allo-
cations by calling set_new_handler (include <new>). This
function takes a pointer to a handler function with the signa-
ture below:
void new_handler_function( );
NOTE
I did not use new_handler as the name for my function to
deal with failed allocations, because that’s a type defined
by the standard for new handlers.
Memory Reclamation
The operators used to reclaim dynamically allocated mem-
ory are delete and delete[].
delete
To reclaim memory previously allocated using new, you use
the delete operator. For example:
WARNING
To ensure that the proper destructors are called, the
pointer used with delete must have the same type as the
pointer used with new when the memory was allocated, or
be a base class pointer.
delete[ ]
To reclaim the memory for an array previously allocated
using new[], you use the delete[] operator. For example:
Circle *ca = new Circle[8];
...
delete[] ca;
WARNING
As with delete, the pointer used with delete[ ] must have
the same type as the pointer used with new[ ] when the
memory was allocated, or be a base class pointer.
C-Style Casts
C-style casting is the form of casting inherited from C. The
target type is placed in parentheses immediately preceding
the expression to be converted, as shown in the assignment
to c below:
void *v = new Circle(5.0);
Circle *c = (Circle *)v;
Casts in C++
C++ provides additional forms of casting, which are gener-
ally safer than C-style casts.
dynamic_cast
The dynamic_cast operator casts a pointer of one class type to
a pointer of another within a derivation chain. It is allowed
only with pointers and references to polymorphic types,
which are types that have at least one virtual member func-
tion (see “Virtual Member Functions”). For the examples
that follow, consider the following derivation chain:
CheckingAccount c;
// Perform an upcast.
a = dynamic_cast<Account *>(&c);
This example shows the three operations you are able to per-
form with the dynamic_cast operator:
upcasting
The pointer is moved up the derivation chain to a base
class.
downcasting
The pointer is moved down the derivation chain to a
derived class.
cross casting
The pointer is moved to a sibling class within the deriva-
tion chain.
NOTE
Since some compilers do not enable runtime type infor-
mation by default, ensure that runtime type information
is turned on for dynamic_cast to work properly.
const_cast
You use the const_cast operator to cast away the const and
volatile qualifiers. It has the same syntax as dynamic_cast.
Between the angle brackets, you specify the same type as the
original, without the const or volatile qualifier. Using the
result is assured to be safe only if the data to which the
pointer points was not declared as const or volatile when it
was first declared in the program.
reinterpret_cast
The reinterpret_cast allows you to convert a pointer to any
other pointer type. It also allows you to convert any integral
type to a pointer and back. It uses a syntax like the other
forms of casting specific to C++. It is typically used
sparingly.
typeid
To get type information about a variable or a type itself, you
use the typeid operator. For example:
Circle c(5.0);
const type_info &t = typeid(c);
type_info
The standard type_info class encapsulates support for work-
ing with type information. It overloads the == and != opera-
tors so that you can easily compare type_info objects. For
example:
if (typeid(a) == typeid(b))
{
// a and b have the same type.
}
Exception Handling
Exception handling is performed using try and catch blocks.
For example:
try
{
// Watch out for a bad file name
// or no file handles available.
}
catch (BadFileName &e)
{
// Handle BadFileName exceptions.
}
catch (HandlesGone &e)
{
// Handle HandlesGone exceptions.
}
try
A try block delineates a context in which exceptions may be
raised, or thrown. When an exception is thrown within a try
block, execution immediately jumps to the start of a catch
block responsible for dealing with the exception, if such a
block exists.
throw
You throw an exception inside a try block using the throw
operator. For example:
throw e;
catch
One or more catch blocks follow a try block to define how
specific types of exceptions should be handled. catch blocks
are tried in the order they appear. The first catch block found
to match the exception’s type or its base class is passed the
exception to handle. Therefore, if you catch exceptions of
both a derived class and its base class, the catch block for the
derived class needs to appear first.
NOTE
Exceptions are often declared as references in catch
blocks so that polymorphic behavior is possible when ac-
cessing the objects to handle the exceptions.
Exception Specifications
An exception specification is a guarantee to the caller of a
function that only certain exceptions can be thrown within
it. For example:
void fetch(char *name, char *&data)
throw (BadFileName, HandlesGone);
I/O Streams
I/O streams are the preferred means of performing input and
output via standard I/O and files in C++. Four streams are
predefined for standard I/O: cin, cout, cerr, and clog. When
writing output, it is common to use the endl manipulator for
newlines.
cin
The cin object controls input from a stream buffer associ-
ated with the C stream stdin. To use cin, you include the
header file <iostream>. The type of cin is istream. The
istream class overloads the >> operator so that you can use it
to read values into variables of intrinsic types. For example:
double value;
The wcin object is the analog to cin for working with wide-
character streams (see “char and wchar_t”).
cout
The cout object controls output to a stream buffer associ-
ated with the C stream stdout. To use cout, you include the
header file <iostream>. The type of cout is ostream. The
ostream class overloads the << operator so that you can use it
to write variables of intrinsic types as output. For example:
char s[] = "Hello";
The wcout object is the analog to cout for working with wide-
character streams (see “char and wchar_t”).
cerr
The cerr object controls output to a stream buffer associ-
ated with the C stream stderr. To use cerr, you include the
header file <iostream>. Aside from working with stderr,
which is unbuffered, the mechanics of cerr are similar to
those described previously for cout. The wcerr object is the
analog to cerr for working with wide-character streams (see
“char and wchar_t”).
clog
Like cerr, the clog object controls output to a stream buffer
associated with the C stream stderr; however, output is buff-
ered. To use clog, you include the header file <iostream>.
The wclog object is the analog to clog for working with wide-
character streams (see “char and wchar_t”).
We’d like to hear your suggestions for improving our indexes. Send email to
[email protected].
125
arrays, 19–22 conditional expression operator
initializer list for, 21 (:?), 45
initializing with an array, 22 const qualifier, 57
multidimensional, 20 const_cast operator, 39, 115
passing to functions, 21 constant data members, 72
assignment operators, 34, 45 constant member functions, 77
overloading, 107 constructors, 80–83
atof( ) function, 5 converting, 30
auto storage class, 56 copy, 81
default, 81
B explicit, 82
inheritance and, 89
backslash (\), 8 member initializers, 83
base classes, 89 continue statement, 64
virtual, 97 copy constructors, 81
bitwise AND operator (&), 43 cout object, 123
bitwise NOT operator (˜), 40 _ _cplusplus macro, 12
bitwise OR operator (|), 43 .cpp files, 7
bitwise XOR operator (^), 43 cross casting, 114
break statement, 64 C-style cast operator, 42
C-style casting, 112
C
C Standard Library, 121 D
C++ programs data members
startup, 3–5 constant, 72
structure, 3–12 declaring, 70–73
termination, 5 mutable, 73
C++ Standard Library, 120–124 static, 71
C, compatibility with, 2 volatile, 73
catch blocks, 118 _ _DATE_ _ macro, 11
cerr object, 124 declarations, 50–58
character escape sequences, 14 forward, 86
character literals, 14 nested, 85
cin object, 122 default arguments, 53
class scope, 47 #define directive, 6, 8
class types, 28 delete operator, 42, 110
classes, 69–86 delete[ ] operator, 42, 111
storage, 55–56 dereferencing pointers, 24, 41
clog object, 124 derived classes, 89
clone member function, 108 destructors, 83
comments, 32 inheritance and, 90
compound statements, 59 virtual, 90
compound types, 17–28 directives, preprocessor, 8–11
126 | Index
division operator (/), 42 functions
do loop, 60 declaring, 52
double type, 16 definitions, 53
downcasting, 114 inline, 54
dynamic_cast operator, 39, overloading, 104
112–114 parameters, 53
passing arrays to, 21
E fundamental types, 12–17
#elif directive, 9
ellipsis (...) and exception G
handling, 118 global namespaces, 66
#else directive, 9 goto statement, 65
enclosing scopes, 49
#endif directive, 6, 9 H
enum keyword, 18
enumerations, 18 header files, 5–7
#error directive, 10 C++ Standard Library, 120
escape sequences, 14 wrapping, 6
exception handling, 117–120
ellipsis (...) and, 118 I
exception specifications, 119 I/O streams, 122
exit function, 5 identifiers, 32
explicit specialization rules, 33
of template classes, 100 #if directive, 9
of template functions, 102 if statement, 62
expression statements, 59 #ifdef directive, 9
expressions, 46 #ifndef directive, 6, 9
extern storage class, 56 implicit conversions, 29
#include directive, 6, 10
F indirection operator (*), 41
file scope, 48 inheritance, 88–98
_ _FILE_ _ macro, 11 access levels for, 94
float type, 16 constructors and, 89
floating points, 16 destructors and, 90
for loops, 61 multiple, 95
break statements and, 64 initializer list for arrays, 21
forward declarations, 86 inline functions, 54
friends, 79 inline keyword, 54
function call operator, 38 int type, 15
function pointers, 25 integers, 15
iteration statements, 60–62
Index | 127
J mutable data members, 73
jump statements, 64 mutable storage class, 56
L N
left shift operator (<<), 43 namespace scope, 48
#line directive, 10 namespaces, 66–68
_ _LINE_ _ macro, 11 global, 66
literals, 34 unnamed, 68
local scope, 47 nested declarations, 85
logical AND operator (&&), 44 new operator, 42, 108
logical NOT operator (!), 40 new[ ] operator, 42, 109
logical OR operator (||), 44 null pointers, 25
long double type, 16 null statements, 59
long type, 15
loops, 60–62 O
l-values, 28 .o files, 7
references as, 28 .obj files, 7
objects
M accessing members, 69
main( ) function, 3 declaring, 69
member access levels, 78 operators, 34–46
member functions, 74–78 list of, 35–37
constant, 77 overloading, 105–108
static, 76 precedence, 35
this pointer and, 75 overloading
virtual, 91–94 defined, 104
volatile, 78 functions, 104
member functions and volatile operators, 105–108
qualifiers, 58
member initializers, 82 P
member selection operator parameters, function, 53
(. and ->), 38 plus operator (+), 41
memory allocation failure, 110 pointer arithmetic, 24
memory management, 108–111 pointer variables, 51
operators, 108 pointers, 24–27
memory reclamation, 110 const declaration, 57
message directive, 11 dereferencing, 24, 41
minus operator (-), 41 function, 25
modulus operator (%), 42 null, 25
multidimensional arrays, 20 of type void, 25
multiple inheritance, 95 this, 75
multiplication operator (*), 42
128 | Index
pointers to members, 26 file, 48
pointer-to-member selection local, 47
operators (.* and –>*), 42 namespace, 48
postfix increment and decrement selection statements, 62
operators (++, --), 39 sequence operator (,), 46
#pragma directive, 11 set_new_handler function, 110
precedence, operator, 35 set_terminate function, 119
prefix increment and decrement shift operators, 43
operators, 40 short type, 15
preprocessor directives, 8–11 signed integers, 15
preprocessor macros, 11 sizeof operator, 40
private members, 78 source files, 7
inheritance and, 95 Standard Template Library
protected members, 78 (STL), 122
inheritance and, 95 statements, 59–65
prototypes, 53 static data members, 71
public members, 78 static member functions, 76
inheritance and, 95 static storage class, 55
static_cast operator, 39, 115
Q std namespace, 121
_ _STDC_ _ macro, 12
qualifiers, 57 STL (Standard Template
Library), 122
R storage classes, 55–56
reference parameters, 27 string literals, 23
references, 27 strings, 22
as l-values, 28 strlen function, 23
register storage class, 56 structs, 86
reinterpret_cast operator, 39, subtraction operator (-), 42
115 switch statement, 63
relational operators, 43
reserved words, 33 T
return statement, 65 template classes, 98–101
right shift operator (>>), 43 default arguments for, 101
RTTI (runtime type explicit specialization of, 100
information), 115 member functions in, 99
nontype parameters in, 100
S template functions, 101–103
scope resolution operator (::), 37 arguments to, 102
scopes, 47–50 explicit specialization of, 102
class, 47 instantiation of, 102
enclosing, 49 nontype parameters in, 103
templates, 98–103
Index | 129
this pointer, 75 V
throw operator, 46, 117 value construction operator, 39
_ _TIME_ _ macro, 11 variables
_ _TIMESTAMP_ _ macro, 11 declarations, 51
tokens, 31 initializing, 52
try block, 117 virtual base classes, 97
type cast operators, 39 virtual destructors, 90
type conversions, 28–30 virtual member functions, 91–94
type definitions, 31 void pointers, 25
type_info class, 116 void type, 17
typedef keyword, 28, 31 volatile data members, 73
typeid operator, 39, 116 volatile member functions, 78
types volatile qualifier, 58
compound, 17–28 member functions and, 58
fundamental, 12–17
W
U
while loop, 60
unary minus and plus operators wide characters, 23
(-, +), 41 wrapping header files, 6
#undef directive, 9
unexpected function, 119
unions, 86
unnamed namespaces, 68
unsigned integers, 15
upcasting, 114
user-defined conversions, 29
using declaration, 67
using directives, 67
130 | Index