In C++ there are two ways of type conversions: implicit and explicit type conversions. The latter are called type casts and they are what this post is about.

Overview

C++ has the following capabilities for explicit type conversions:

The C++ cast operators are keywords defined in the language. While they look like template functions, they are part of the language itself, i.e.the behavior is implemented in the compiler, not in the standard library. There are four of them: `const_cast` `reinterpret_cast` `static_cast` `dynamic_cast`

The C-style and function-style casts. The C-style cast consists of the type you want in parentheses, followed by the expression you want to be converted into that type, e.g. `(double)getInt()`. The function style cast works only slightly different, by stating the target type followed by the source expression in parentheses, i.e. `double(getInt())`. It is equivalent to the C-style cast in every respect, except the target type has to be a single word, so `unsigned long`, `const double` and any kind of pointer or reference is not allowed.

Construction of a temporary value in C++11. It looks similar to the function-style cast: `long{getInt()}` but uses the initializer list with curly braces introduced in C++11. It has a few more restrictions than the function-style cast, e.g. if converting to a user-defined type that is only possible when the target type has a corresponding constructor, but not when the source type has a corresponding conversion operator.

Functions that take a parameter of one type and return an object of another type, representing the same value. While they are technically not real casts, they have the same look and feel and usage, and sometimes even are implemented with casts. Prominent examples are `std::move`, `std::dynamic_pointer_cast` and `boost::lexical_cast`.

The four cast operators represent the basic conversions possible in C++, so I will explain them in detail. The other possibilities will be covered only briefly.

const_cast

This cast has one sole purpose: removing constness from a pointer or reference. In theory, it is also usable to add constness, but since this is possible via an implicit conversion, it is not recommended to explicitly use a cast for that. It is the only cast operator that can remove the constness, other cast operators are not allowed to do so.

void foo(MyClass const& myObject) { MyClass& theObject = const_cast<MyClass&>(myObject); // do something with theObject }

Casting away the constness of an object can be dangerous. In the example above, the user of the function will expect his object to remain unchanged. The const_cast on the other hand gives full write access to the object so it could be changed. Irresponsible use of const_cast therefore can lead to unexpected behavior, hard to debug bugs and even undefined behavior.

In many cases const_cast is only necessary due to design problems. Const correctness is often missing in legacy code or it is perceived hard to get right because developers mix up semantic and syntactic constness or don’t use mutable when appropriate.

Be suspicious whenever you encounter a const_cast in code. Think twice before you write one.

There are a few cases where const_cast is indeed the right thing to do. The best-known cases are accessor functions that have a const and a non-const version, where the former returns a const reference (or pointer) and the latter a non-const reference:

class MyContainer { int* data; public: int& getAt(unsigned index) { auto const_this = static_cast<MyContainer const*>(this); return const_cast<int&>(const_this->getAt(index)); } int const& getAt(unsigned index) const { checkIndex(index); return data[index]; } };

More general, const_cast is then used to access a const object in a way that syntactically might change the object, but you know for sure that it does not. This is mostly restricted to the object’s own methods since encapsulation demands that outsiders cannot be sure when a non-const operation does not alter the object.

reinterpret_cast

reinterpret_cast is the most aggressive, insecure and (hopefully) least used of the four C++ cast operators. It can be used only on integral types, enums, all kinds of pointers including function and member pointers and nullpointer constants like std::nullptr . It is meant to be used to convert types that are otherwise not compatible, i.e. mainly from pointer to int and back, or from pointer to X to pointer to Y and back, where X and Y are unrelated types.

The usual behavior is to just reinterpret the bit representation of the source value as bit representation of the target value. No checks are applied, which means if you use the cast, you are on your own. For example, you can indeed cast a car* into a duck* , and casting it back is guaranteed to give you the same car* . Actually using the duck* will most surely result in undefined behavior. In fact, any use of reinterpret_cast that can not be done via other casts has a bunch of “DANGER” and “Undefined Behavior” signs around it.

I know of only two examples I know of where there is no option but to use reinterpret_cast are casting pointer values to int, to log them in the well known 0x50C0FFEE format and storing a pointer where another pointer (or int) is meant to be stored. The latter is e.g. the case in Borland’s VCL where GUI objects have the ability to store data in a TObject pointer. If you want to store a context that is not derived from TObject you have to store and retrieve it by casting your object’s address to and from TObject* . void* would have been a better choice in my opinion.

If you need to write a `reinterpret_cast`, make a break, go for a walk, and reconsider that decision. If you come back and still want to write it, encapsulate the cast(s) carefully.

static_cast

static_cast is the most straightforward cast. Consider you have an expression a of type A and want that value converted to type B , and the conversion is possible per sé, i.e. the types are not unrelated so you don’t need a reinterpret_cast . If the conversion is not implicit, or the compiler is not able to select the right implicit conversion because you passed the value to a function that has overloads that get preferred over the one you want or make it ambiguous, then you have to explicitly force the conversion.

If B is a user-defined class type it is common to use a function-style cast or call the conversion constructor explicitly, i.e. B(a) or B{a} . Both have the same effect as a static_cast in this case. In all other cases, i.e. if you convert to or between built-in types, use static_cast explicitly. Cases, where this is necessary, are:

narrowing conversions between numbers (int to short, double to int, …) conversions between integrals and enums conversion from `void*` to any other pointer type downcasts of pointers or references in class hierarchies when you know the dynamic type of the object (see below)

Points 3 and 4 are to be used with caution: If you static_cast to a pointer (or reference) of type T* , the compiler believes you and assumes you really know that in fact there is a T at the address stored in the pointer. If there is something else, it will still treat the bits and bytes at that location as if there was a T , causing undefined behavior and hopefully blowing the program up right in your face. (I say hopefully because a crash is much less pain to debug than a silent failure that lets the program just act weird but continue).

dynamic_cast

This cast is used for downcasts and cross-casts of pointers and references in class hierarchies. You pass in a pointer of class X, casting it to a pointer of a class somewhere else in the class hierarchy. Casting to a base class (upcast) is implicitly possible and does not need an explicit cast.

Depending on whether the type of the object behind that pointer (called the dynamic type) in fact is of that other class or not, the result of the cast is the new pointer or a null pointer. Of course, if the object is of a type that is derived from the target class, the cast succeeds as well. Since references cannot be null, dynamic_cast on a reference throws an std::bad_cast exception if the cast does not succeed.

class B {}; class D1: public B {}; class D2: public B {}; void foo() { D1 d1; D2 d2; B* b1 = &d1; B* b2 = &d2; D1* d1b1 = dynamic_cast<D1*>(b1); //ok, d1b1 now points to d1 D1* d1b2 = dynamic_cast<D1*>(b2); //result is NULL because *b2 is not a D1 D1& rd1b2 = dynamic_cast<D1&>(*b2); //throws std::bad_cast }

People often view the presence of dynamic_cast with suspicion because it is often a hint to a flawed design. Many naive applications of dynamic_cast can be solved more cleanly with virtual functions.

Before applying a dynamic_cast, check if the problem at hand can not better be solved with virtual functions.

Downcasts in class hierarchies

dynamic_cast , static_cast and reinterpret_cast can all three be used to cast a base class pointer or reference into a pointer or reference to a more derived class. So what is the difference between the three?

As shown above, dynamic_cast checks if the dynamic type of the object is of the expected class. That check is performed at runtime which needs access to runtime type information (RTTI) and costs a few CPU cycles. The other two casts occur (almost) purely at compile time and are therefore faster. However, if you do not know the dynamic type of the object, you have no other option.

If you know the dynamic type and the relationship between the two classes is a line of single inheritances, then the two other casts do exactly the same, which is exactly nothing. The new pointer contains the exact same address, it just has another type. However, in case of static_cast the compiler checks if that conversion is even possible, i.e. if the target type is indeed a derived class of the source type, so it is more secure than reinterpret_cast . The following example will lead to a compiler error:

class B; //forward declaration class D; //forward declaration B* pb; D* pd = static_cast<D*>(pb); //ERROR: B* is not convertible to D*

In case of multiple inheritance, the memory layout may be in a way that the address of the derived object differs from the address of the base class object:

class B1 { int i; }; class B2 { int j; }; class D : public B1, public B2 {}; void bar() { D d; B2* pb2 = &d; D* pd1 = static_cast<D*>(pb2); D* pd2 = reinterpret_cast<D*>(pb2); }

Let’s assume for simplicity that sizeof(int) is 4, and there are no padding bytes, and we are in a typical environment where the subobjects are stored in order in memory. Compared to the address of d itself, the offset of the B1 subobject and its member i is 0, i.e. they have the same address. The offset of the B2 subobject and j is 4.

When the compiler sees the line B2* pb2 = &d; it knows that offset and performs the implicit conversion from D* to B2* by adding 4, so that pointer does indeed point to the B2 subobject. The static_cast is doing the exact opposite: The compiler subtracts 4 and pd1 has again the address with offset 0, pointing correctly to d . The reinterpret_cast on the other hand will preserve the value of pb2 , so pd2 will contain the same address, pointing to offset 4 and not to d . Accessing it will result in undefined behavior. Oops.

For downcasts use either dynamic_cast or static_cast, never reinterpret_cast.

C-style cast and function-style cast

When the compiler sees a C-style or function style cast, it tries to apply different sequences of elementary conversion. The first one that is possible is applied. The sequences are in order:

`const_cast` `static_cast` `static_cast` followed by `const_cast` `reinterpret_cast` `reinterpret_cast` followed by `const_cast`

As seen above, reinterpret_cast is very unsafe, so you don’t want the compiler to accidentally apply that one. As a corollary, you don’t want to use these casts to convert something to pointers, references or other built-in types. const_cast can be applied only to pointers and references that we have ruled out already, so what remains is a sole application of static_cast . That is the reason why I mentioned the possibility of function style casts to user-defined types in the static_cast section. Since that leaves no composed types as target types, the C-style form is never necessary and therefore discouraged. Instead of a C-style cast, you can also use the constructor call conversion.

Use function-style cast for conversions to user-defined classes only. Don’t use C-style casts.

Conclusion