A pointer to a const object can be converted to a pointer to non-const object using the const_castkeyword(opens new window). Here we use const_cast to call a function that is not const-correct. It only accepts a non-const char* argument even though it never writes through the pointer:
voidbad_strlen(char*);constchar* s ="hello, world!";bad_strlen(s);// compile errorbad_strlen(const_cast<char*>(s));// OK, but it's better to make bad_strlen accept const char*
const_cast to reference type can be used to convert a const-qualified lvalue into a non-const-qualified value.
const_cast is dangerous because it makes it impossible for the C++ type system to prevent you from trying to modify a const object. Doing so results in undefined behavior.
constint x =123;int& mutable_x =const_cast<int&>(x);
mutable_x =456;// may compile, but produces *undefined behavior*
C-style casting
C-Style casting can be considered 'Best effort' casting and is named so as it is the only cast which could be used in C. The syntax for this cast is (NewType)variable.
Whenever this cast is used, it uses one of the following c++ casts (in order):
Functional casting is very similar, though as a few restrictions as the result of its syntax: NewType(expression). As a result, only types without spaces can be cast to.
It's better to use new c++ cast, because s more readable and can be spotted easily anywhere inside a C++ source code and errors will be detected in compile-time, instead in run-time.
As this cast can result in unintended reinterpret_cast, it is often considered dangerous.
Base to derived conversion
A pointer to base class can be converted to a pointer to derived class using static_cast. static_cast does not do any run-time checking and can lead to undefined behaviour when the pointer does not actually point to the desired type.
structBase{};structDerived:Base{};
Derived d;
Base* p1 =&d;
Derived* p2 = p1;// error; cast required
Derived* p3 =static_cast<Derived*>(p1);// OK; p2 now points to Derived object
Base b;
Base* p4 =&b;
Derived* p5 =static_cast<Derived*>(p4);// undefined behaviour since p4 does not// point to a Derived object
Likewise, a reference to base class can be converted to a reference to derived class using static_cast.
If the source type is polymorphic, dynamic_cast can be used to perform a base to derived conversion. It performs a run-time check and failure is recoverable instead of producing undefined behaviour. In the pointer case, a null pointer is returned upon failure. In the reference case, an exception is thrown upon failure of type std::bad_cast (or a class derived from std::bad_cast).
structBase{virtual~Base();};// Base is polymorphicstructDerived:Base{};
Base* b1 =new Derived;
Derived* d1 =dynamic_cast<Derived*>(b1);// OK; d1 points to Derived object
Base* b2 =new Base;
Derived* d2 =dynamic_cast<Derived*>(b2);// d2 is a null pointer
Conversion between pointer and integer
An object pointer (including void*) or function pointer can be converted to an integer type using reinterpret_cast. This will only compile if the destination type is long enough. The result is implementation-defined and typically yields the numeric address of the byte in memory that the pointer pointers to.
Typically, long or unsigned long is long enough to hold any pointer value, but this is not guaranteed by the standard.
If the types std::intptr_t and std::uintptr_t exist, they are guaranteed to be long enough to hold a void* (and hence any pointer to object type). However, they are not guaranteed to be long enough to hold a function pointer.
Similarly, reinterpret_cast can be used to convert an integer type into a pointer type. Again the result is implementation-defined, but a pointer value is guaranteed to be unchanged by a round trip through an integer type. The standard does not guarantee that the value zero is converted to a null pointer.
voidregister_callback(void(*fp)(void*),void* arg);// probably a C APIvoidmy_callback(void* x){
std::cout <<"the value is: "<<reinterpret_cast<long>(x);// will probably compile}long x;
std::cin >> x;register_callback(my_callback,reinterpret_cast<void*>(x));// hopefully this doesn't lose information...
Type punning conversion
A pointer (resp. reference) to an object type can be converted to a pointer (resp. reference) to any other object type using reinterpret_cast. This does not call any constructors or conversion functions.
int x =42;char* p =static_cast<char*>(&x);// error: static_cast cannot perform this conversionchar* p =reinterpret_cast<char*>(&x);// OK*p ='z';// maybe this modifies x (see below)
The result of reinterpret_cast represents the same address as the operand, provided that the address is appropriately aligned for the destination type. Otherwise, the result is unspecified.
int x =42;char& r =reinterpret_cast<char&>(x);constvoid* px =&x;constvoid* pr =&r;assert(px == pr);// should never fire
The result of reinterpret_cast is unspecified, except that a pointer (resp. reference) will survive a round trip from the source type to the destination type and back, as long as the destination type's alignment requirement is not stricter than that of the source type.
int x =123;unsignedint& r1 =reinterpret_cast<unsignedint&>(x);int& r2 =reinterpret_cast<int&>(r1);
r2 =456;// sets x to 456
On most implementations, reinterpret_cast does not change the address, but this requirement was not standardized until C++11.
reinterpret_cast can also be used to convert from one pointer-to-data-member type to another, or one pointer-to-member-function type to another.
Use of reinterpret_cast is considered dangerous because reading or writing through a pointer or reference obtained using reinterpret_cast may trigger undefined behaviour when the source and destination types are unrelated.
Conversion by explicit constructor or explicit conversion function
A conversion that involves calling an explicit(opens new window) constructor or conversion function can't be done implicitly. We can request that the conversion be done explicitly using static_cast. The meaning is the same as that of a direct initialization, except that the result is a temporary.
classC{
std::unique_ptr<int> p;public:explicitC(int* p):p(p){}};voidf(C c);voidg(int* p){f(p);// error: C::C(int*) is explicitf(static_cast<C>(p));// okf(C(p));// equivalent to previous line
C c(p);f(c);// error: C is not copyable}
Implicit conversion
static_cast can perform any implicit conversion. This use of static_cast can occasionally be useful, such as in the following examples:
When passing arguments to an ellipsis, the "expected" argument type is not statically known, so no implicit conversion will occur.
constdouble x =3.14;printf("%d\n",static_cast<int>(x));// prints 3// printf("%d\n", x); // undefined behaviour; printf is expecting an int here// alternative:// const int y = x; printf("%d\n", y);
Without the explicit type conversion, a double object would be passed to the ellipsis, and undefined behaviour would occur.
A derived class assignment operator can call a base class assignment operator like so:
static_cast can convert from an integer or floating point type to an enumeration type (whether scoped or unscoped), and vice versa. It can also convert between enumeration types.
The conversion from an unscoped enumeration type to an arithmetic type is an implicit conversion; it is possible, but not necessary, to use static_cast.
When a scoped enumeration type is converted to an arithmetic type:
- If the enum's value can be represented exactly in the destination type, the result is that value.
- Otherwise, if the destination type is an integer type, the result is unspecified.
- Otherwise, if the destination type is a floating point type, the result is the same as that of converting to the underlying type and then to the floating point type.
Example:
enumclassFormat{
TEXT =0,
PDF =1000,
OTHER =2000,};
Format f = Format::PDF;int a = f;// errorint b =static_cast<int>(f);// ok; b is 1000char c =static_cast<char>(f);// unspecified, if 1000 doesn't fit into chardouble d =static_cast<double>(f);// d is 1000.0... probably
When an integer or enumeration type is converted to an enumeration type:
- If the original value is within the destination enum's range, the result is that value. Note that this value might be unequal to all enumerators.
- Otherwise, the result is unspecified (<= C++14) or undefined (>= C++17).
Example:
enumScale{
SINGLE =1,
DOUBLE =2,
QUAD =4};
Scale s1 =1;// error
Scale s2 =static_cast<Scale>(2);// s2 is DOUBLE
Scale s3 =static_cast<Scale>(3);// s3 has value 3, and is not equal to any enumerator
Scale s9 =static_cast<Scale>(9);// unspecified value in C++14; UB in C++17
When a floating point type is converted to an enumeration type, the result is the same as converting to the enum's underlying type and then to the enum type.
enumDirection{
UP =0,
LEFT =1,
DOWN =2,
RIGHT =3,};
Direction d =static_cast<Direction>(3.14);// d is RIGHT
Derived to base conversion for pointers to members
A pointer to member of derived class can be converted to a pointer to member of base class using static_cast. The types pointed to must match.
If the operand is a null pointer to member value, the result is also a null pointer to member value.
Otherwise, the conversion is only valid if the member pointed to by the operand actually exists in the destination class, or if the destination class is a base or derived class of the class containing the member pointed to by the operand. static_cast does not check for validity. If the conversion is not valid, the behaviour is undefined.
structA{};structB{int x;};structC:A,B{int y;double z;};int B::*p1 =&B::x;int C::*p2 = p1;// ok; implicit conversionint B::*p3 = p2;// errorint B::*p4 =static_cast<int B::*>(p2);// ok; p4 is equal to p1int A::*p5 =static_cast<int A::*>(p2);// undefined; p2 points to x, which is a member// of the unrelated class Bdouble C::*p6 =&C::z;double A::*p7 =static_cast<double A::*>(p6);// ok, even though A doesn't contain zint A::*p8 =static_cast<int A::*>(p6);// error: types don't match
void* to T*
In C++, void* cannot be implicitly converted to T* where T is an object type. Instead, static_cast should be used to perform the conversion explicitly. If the operand actually points to a T object, the result points to that object. Otherwise, the result is unspecified.
Even if the operand does not point to a T object, as long as the operand points to a byte whose address is properly aligned for the type T, the result of the conversion points to the same byte.
// allocating an array of 100 ints, the hard wayint* a =malloc(100*sizeof(*a));// error; malloc returns void*int* a =static_cast<int*>(malloc(100*sizeof(*a)));// ok// int* a = new int[100]; // no cast needed// std::vector<int> a(100); // betterconstchar c ='!';constvoid* p1 =&c;constchar* p2 = p1;// errorconstchar* p3 =static_cast<constchar*>(p1);// ok; p3 points to cconstint* p4 =static_cast<constint*>(p1);// unspecified in C++03;// possibly unspecified in C++11 if// alignof(int) > alignof(char)char* p5 =static_cast<char*>(p1);// error: casting away constness
Syntax
simple-type-specifier()
simple-type-specifier(expression-list)
simple-type-specifierbraced-init-list
typename-specifier()
typename-specifier(expression-list)
typename-specifierbraced-init-list
dynamic_cast<type-id>(expression)
static_cast<type-id>(expression)
reinterpret_cast<type-id>(expression)
const_cast<type-id>(expression)
(type-id)cast-expression
Remarks
All six cast notations have one thing in common:
Casting to an lvalue reference type, as in dynamic_cast<Derived&>(base), yields an lvalue. Therefore, when you want to do something with the same object but treat it as a different type, you would cast to an lvalue reference type.
Casting to an rvalue reference type, as in static_cast<string&&>(s), yields an rvalue.
Casting to a non-reference type, as in (int)x, yields a prvalue, which may be thought of as a copy of the value being cast, but with a different type from the original.
The reinterpret_cast keyword is responsible for performing two different kinds of "unsafe" conversions:
The "type punning"(opens new window) conversions, which can be used to access memory of one type as though it is of a different type.
The static_cast keyword can perform a variety of different conversions:
[Base to derived](http://stackoverflow.com/documentation/c%2b%2b/3090/explicit-type-conversions/10518/base-to-derived-conversion) conversions
Any conversion that can be done by a direct initialization, including both implicit conversions and conversions that call an explicit constructor or conversion function. See [here](http://stackoverflow.com/documentation/c%2b%2b/3090/explicit-type-conversions/18732/implicit-conversion) and [here](http://stackoverflow.com/documentation/c%2b%2b/3090/explicit-type-conversions/18731/conversion-by-explicit-constructor-or-explicit-conversion-function) for more details.
To `void`, which discards the value of the expression.
// on some compilers, suppresses warning about x being unusedstatic_cast<void>(x);
Between arithmetic and enumeration types, and between different enumeration types. See [enum conversions](http://stackoverflow.com/documentation/c%2b%2b/3090/explicit-type-conversions/18751/enum-conversions)
From pointer to member of derived class, to pointer to member of base class. The types pointed to must match. See [derived to base conversion for pointers to members](http://stackoverflow.com/documentation/c%2b%2b/3090/explicit-type-conversions/18752/derived-to-base-conversion-for-pointers-to-members)
[`void*` to `T*`](http://stackoverflow.com/documentation/c%2b%2b/3090/explicit-type-conversions/18753/void-to-t).