
Type Conversion
Implicit Type Conversion
C++ is a strong typed language. All initialization and assignments of identifiers are checked at compile-time to be sure that the types of these values are correctly matched. If they are not and if a rule exists for matching them, the compiler will apply that rule. This rule is referred to as implicit type conversion.
For example, the statements
int m ;
float x = 2 . 531;
m = x ; // ok
convert x to an integer before its value is assigned to m. Thus the fractional part is truncated.
If there is no rule, the statement is flagged as an error.
For example,
int i = 17 ;
int * p = & i ; // ok
unsigned int * pp = & i ; // error no conversion
When the compiler encounters an expression, it divides the experssion into sub-expressions consisting of one operator and one or two operands. For the binary operator, if the operands type differ, the compiler converts one of them to match with the other using a certain rule. The rule is that the "smaller" type is converted to "wider" type. For example, if one of the operand is an int and the other is a float, the int is converted into a float because a float is wider than an int.
Explicit Type Conversion
C++ permits explicit type conversion of variables or expressions using the type cast operator. Sometimes a programmer needs to convert a value from one type to another in a situation where the compiler will not do it automatically. Type conversions specified by the programmer are referred to as cast. The following two notations are used for casts.
( type-name ) expression
type-name ( expression )
average = sum / ( float ) i ;
average = sum / float ( i ) ;
C++ Style Casts
There are four new casting operators specific to the C++ language. These operators are intended to remove some of the ambiguity and danger inherent in old style C-language casts. Each one returns an object converted according to the rules of the operator. They use the syntax
cast _ operator <Type> ( object )
where the cast_operator is one of the following
static_cast
const_cast
dynamic_cast
reinterpret_cast
The Type argument is the type being cast to ; and the object argument is the object being cast from.
static_cast
static _ cast has basically the same power and meaning as the general purpose C-style cast. static_cast can be used to perform any implicit conversion.
For example,
char ch ;
int i = 13 ;
ch = static_cast <char> ( i ) ; // int to char
It also has the same kind of restrictions. For example, you can't cast a struct into an int or a double into a pointer. Furthermore, static_cast can't change the constness of an expression, because another new cast, const_cast is designed specifically to do that.
const_cast
const_cast is used to cast away the constness or volatileness of an expression. By using a const_cast, you emphasize that the only thing you want to change through the cast is the constness or volatileness of an expression. If you try to use const_cast for anything other purpose, your casts will be rejected.
class A
{
public :
A ( int v ) : val ( v ) , count ( 0 )
{
}
void readonly ( ) const ;
private :
int val, count ;
} ;
void A : : readonly ( ) const
{
count ++ ; // error
const_cast <A *> ( this ) ->count ++; //ok
}
Within the member function readonly ( ), the const object this was cast to a non-const object of the same type, thereby allowing the programmer to tamper the data member count. The most common use of const_cast is to cast away the constness of an object.
dynamic_cast
dynamic_cast is used to perform safe casts down or across an inheritance hierarchy. That is, you use dynamic_cast to cast pointers or references to base class objects into pointers or references to derived class objects. You can determine whether the casts succeeded. Failed casts are indicated by a null pointer ( when casting pointers ) or an exception ( when casting references )
reinterpret_cast
reinterpret_cast is used to perform type conversions whose result is nearly always implementation-defined. As a result, reinterpret_casts are rarely portable. If for some unsual reason you really need to assign one kind of pointer type to another, you can use the reinterpret_cast.
For example,
int n ;
float m ;
int * ptr1 ;
float * ptr2 ;
ptr1 = reinterpret_cast <int *> ( & m ) ;
ptr2 = reinterpret_cast <float *> ( & n ) ;
The use of reinterpret_cast in this way is not recommended, but occasionally it's the only way out of a difficult situation.