The reason for this operator is that occasionally you may have a need for a value that is constant most of the time but that can be changed occasionally. In such a case, you can declare the value as const and use const_cast when you need to alter the value. This could be done using the general type cast, but the general type cast can also simultaneously change the type:
High bar;
const High * pbar = &bar
...
High * pb = (High *) (pbar); // valid
Low * pl = (Low *) (pbar); // also valid
Because the simultaneous change of type and constantness may be an unintentional programming slip, using the const_cast operator is safer.
The const_cast is not all powerful. It can change the pointer access to a quantity, but the effect of attempting to change a quantity that is declared const is undefined. Let’s clarify this statement with the short example shown in Listing 15.19.
Listing 15.19. constcast.cpp
// constcast.cpp -- using const_cast<>
#include
using std::cout;
using std::endl;
void change(const int * pt, int n);
int main()
{
int pop1 = 38383;
const int pop2 = 2000;
cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
change(&pop1, -103);
change(&pop2, -103);
cout << "pop1, pop2: " << pop1 << ", " << pop2 << endl;
return 0;
}
void change(const int * pt, int n)
{
int * pc;
pc = const_cast
*pc += n;
}
The const_cast operator can remove the const from const int * pt, thus allowing the compiler to accept the following statement in change():
*pc += n;
However, because pop2 is declared as const, the compiler may protect it from any change, as is shown by the following sample output:
pop1, pop2: 38383, 2000
pop1, pop2: 38280, 2000
As you can see, the calls to change() alter pop1 but not pop2. The pointer in change() is declared as const int *, so it can’t be used to change the value of the pointed-to int. The pointer pc has the const cast away, so it can be used to change the pointed-to value, but only if that value wasn’t itself const. Therefore, pc can be used to alter pop1 but not pop2.
The static_cast operator has the same syntax as the other operators:
static_cast <
It’s valid only if
High bar;
Low blow;
...
High * pb = static_cast
Low * pl = static_cast
Pond * pmer = static_cast
The first conversion here is valid because an upcast can be done explicitly. The second conversion, from a base-class pointer to a derived-class pointer, can’t be done without an explicit type conversion. But because the type cast in the other direction can be made without a type cast, it’s valid to use static_cast for a downcast.
Similarly, because an enumeration value can be converted to an integral type without a type cast, an integral type can be converted to an enumeration value with static_cast. Also you can use static_cast to convert double to int, to convert float to long, and to perform the various other numeric conversions.
The reinterpret_cast operator is for inherently risky type casts. It doesn’t let you cast away const, but it does allow other unsavory things. Sometimes a programmer has to do implementation-dependent, unsavory things, and using the reinterpret_cast operator makes it simpler to keep track of such acts. It has the same syntax as the other three operators:
reinterpret_cast <
Here is a sample use:
struct dat {short a; short b;};
long value = 0xA224B118;
dat * pd = reinterpret_cast< dat *> (&value);
cout << hex << pd->a; // display first 2 bytes of value
Typically, such type casts would be used for low-level, implementation-dependent programming and would not be portable. For example, one system may store the bytes in a multibyte value in a different order than does a second system.
The reinterpret_cast operator doesn’t allow just anything, however. For example, you can cast a pointer type to an integer type that’s large enough to hold the pointer representation, but you can’t cast a pointer to a smaller integer type or to a floating-point type. Another restriction is that you can’t cast a function pointer to a data pointer or vice versa.