In an arithmetic expression, binary operators require operands of the same type. If this is not the case, the type of one operand must be converted to match that of the other operand. When calling a function, the argument type must match the parameter type; if it doesn't, the argument is converted so its type matches. C++ has cast operators, which let you define a type conversion explicitly, or you can let the compiler automatically convert the type for you. This section presents the rules for automatic type conversion.
An arithmetic type is a fundamental
integral or floating-point type: bool
, char
, signed
char
, unsigned
char
, int
, short
, long
, unsigned
int
, unsigned
short
, unsigned
long
, float
, double
, or long
double
. Some operations are permitted only
on arithmetic types, pointer types, enumerations, class types, or some
combination of types. The description of each operator tells you which
types the operator supports.
Type promotion is an automatic type conversion that applies only to arithmetic types, converting a "smaller" type to a "larger" type while preserving the original value. Contrast promotions with other automatic type conversions (described in later subsections), which can lose information. Promotions involve either integral or floating-point values. The rules for integral promotion are:
A "small" integral rvalue is converted to an int
if the type int
can represent all of the values of
the source type; otherwise, it is converted to unsigned
int
. A "small" value is an integral
bit-field (see Chapter 6)
whose size is smaller than an int
, or a value with one of the
following types: char
, signed
char
, unsigned
char
, short
int
, unsigned
short
int
.
An rvalue whose type is wchar_t
or an enumeration (including
bit-fields with enumeration type) is converted to the first type
that can hold all the values of the source type. The type is one
of: int
, unsigned
int
, long
, or unsigned
long
.
An rvalue of type bool
can be converted to an int
; the
value true
becomes 1
, and the value false
becomes 0
.
One floating-point promotion rule is defined:
An rvalue of type float
can be converted to type double
.
An arithmetic type conversion is an automatic type conversion that the compiler applies to the operands of the built-in arithmetic and comparison operators. For the arithmetic operators, the result type is the same as the operand type.
The arithmetic type conversions try to preserve the original
values as much as possible. However, they do not always succeed. For
example, -1
/
1u
does
not produce -1
as a result because
-1
has type int
, which is converted to type unsigned
int
, yielding an implementation-defined
arithmetic value. On a 32-bit, two's-complement system, the result is
4294967295u
.
The rules for arithmetic type conversion are applied in the following order:
If one operand has type long
double
, the other is converted to
long
double
.
Otherwise, if one operand is double
, the other is converted to
double
.
Otherwise, if one operand is float
, the other is converted to
float
.
Otherwise, integral promotions are performed (see the section Section 3.2.2).
After integral promotion, if one operand is unsigned
long
, the other is converted to unsigned
long
.
Otherwise, if one operand is long
, and the other is unsigned
int
, type conversion occurs as
follows:
If all values of type unsigned
int
fit in a long
int
, the unsigned
int
is converted to long
int
.
Otherwise, both operands are converted to unsigned
long
.
Otherwise, if one operand is long
, the other is converted to long
.
Otherwise, if one operand is unsigned
, the other is converted to
unsigned
.
Otherwise, both operands are int
.
An arithmetic value can be converted implicitly to a different arithmetic value, even if that conversion loses information. These implicit conversions can take place in assignments, initializers, arguments to function calls, returning values from a function, and template arguments. Do not confuse these conversions with the arithmetic type conversions described earlier, which can take place in any arithmetic operation.
The basic rule is that any arithmetic type can be converted to any other. If the destination type cannot hold the converted value, the behavior is undefined. When assigning a floating-point number to an integer, the floating-point value is truncated toward zero by discarding the fractional part. When converting an integer or enumerated value to a floating-point number, if the integer value falls between two floating-point values (that is, the integer is not representable in the floating-point format), the implementation chooses one of the two neighboring values.
A value can be converted to a class type if the class has a
suitable constructor that does not use the explicit
specifier. A value of class type
can be converted to a non-class type if the source class has a type
conversion operator of the target type. When converting a class type
to another class type, the compiler considers the constructors for the
target class and the type conversion operators for the source
class.
Lvalue conversions automatically convert an lvalue to an rvalue for contexts in which an rvalue is required. The need to convert an lvalue to an rvalue is usually transparent, and these conversions are listed only for the sake of completeness:
An array lvalue can be converted to a pointer rvalue, pointing to the first element of the array.
A function lvalue can be converted to an rvalue pointer to the function.
Any other lvalue can be converted to an rvalue with the same
value. If the type is not a class type,
cv-qualifiers are removed from the type.
Thus, a const
int
lvalue is converted to an int
rvalue.
Arithmetic, enumeration, and pointer values can be converted to
bool
, in which null pointers and zero arithmetic values are
false
, and everything else is
true
. A common idiom is to test
whether a pointer is a null pointer:
if (ptr) ... // Do something with *ptr. else ... // Pointer is null if (! ptr) // Another way to test if ptr is null
This idiom is so common that some classes have operators to
convert an object to void*
, so
void*
can be converted to bool
. (Any pointer type would do, but
void*
is used because the pointer
is not meant to be dereferenced, only converted to bool
.) The void*
operator is used instead of a direct
conversion to bool
to avoid
automatic promotion to an integer. For example, basic_ios
defines operator
void*(
)
to return a null pointer if the iostream
's failbit
is set. (See <ios>
in Chapter 13 for details.)
A type cast is an explicit type conversion. C++ offers several different ways to cast an expression to a different type. The different ways expose the evolution of the language. The six forms of type cast expressions are:
(
type
)
expr
type
(
expr
)
const_cast<
type
>(
expr
)
dynamic_cast<
type
>(
expr
)
reinterpret_cast<
type
>(
expr
)
static_cast<
type
>(
expr
)
The first form was inherited from C; the second form was added in the early days of C++ and has the same meaning as the first, but with a slightly different syntax. The final four forms supplant the two older forms and are preferred because they are more specific, thus reducing the risk of error. All type cast expressions are described in detail later in this chapter; the first form is covered in the section Section 3.5.4, and the other five forms are covered in Section 3.5.2. The remainder of this section briefly discusses when to use each form.
If you simply want to force an expression to be const
, or to remove a const
(e.g., prior to passing a pointer to a
legacy library that is not written in C++ and does not know about
const
declarations), use const_cast<>
. (You can also change the volatile
qualifier, but that is less
common.)
If you have a pointer or reference to an object whose declared
type is a base class, but you need to obtain a derived class pointer
or reference, you should use dynamic_cast<>
. The dynamic cast performs a runtime check to make sure
the cast is valid. A dynamic cast works only with polymorphic classes,
which have at least one virtual function.
The common uses of static_cast<>
are to force one enumeration to a different enumerated
type, force an arithmetic type to a different type, or force a
particular conversion from a class-type object that has multiple type
conversion operators. The simpler type casts are sometimes used in
these cases, for the sake of brevity. For example, sqrt(float(i))
can be easier to read than
sqrt(static_cast<float>(i))
.
Use static_cast
to reverse any
implicit type conversion. For example, C++ automatically converts an
enum
to an integer; use static_cast
if you want to convert an
integer to an enum
. You can use
static_cast
to cast a pointer to
and from void*
.
A reinterpret_cast<>
is reserved for potentially unsafe type casts, such as
converting one type of pointer to another. You can also convert a
pointer to an integer or vice versa. For example, an internal
debugging package might record debug log files. The logger might
convert pointers to integers using reinterpret_cast<>
and print the
integers using a specific format.
If you try to perform the wrong kind of cast with one of the
template-like cast operators, the compiler informs you of your
mistake. For example, if you use static_cast<>
and accidentally cast
away const
-ness, the compiler
complains. Or if you use static_cast<>
where you should have
used reinterpret_cast<>
, the
compiler complains. The short forms of casting do not provide this
extra level of error-checking because one form must suffice for the
several different kinds of type casts.
When you see a type cast, you should read it as a warning that something unusual is happening. The longer forms of type casts provide additional clues about the programmer's intent, and help the compiler enforce that intent.