Type casting in C++

This post will introduce four specific casting operators that are most frequently used in C++ project. They include static_cast, dynamic_cast, const_cast and reinterpret_cast. The differences between of them will be told with some code samples.

staic_cast <type-id> (expression)

staic_cast should be the first considered operator for type conversion. It can perform upcast and downcast conversion but does not perform any type-safety checks. So, staic_cast is not a safe opeation for downcast conversion and up to programers to ensure the conversion is safe. However, staic_cast does not incur the overhead of the type-safety checks.

dynamic_cast <type-id> (expression)

dynamic_cast should be used for conversion of pointers or references to classes. This operator can ensure that the result of type conversion points to a valid complete object.

Conversion by dynamic_cast includes pointer upcast (converting from pointer-to-derived to pointer-to-base) naturally as allowed as an implicit conversion. Specifically, when do a downcast (convert from pointer-to-base to pointer-to-derived) conversion, dynamic_cast will do a type check to ensure the pointed object is a valid complete object of the target type. So, dynamic_cast is a safe operator for downcast conversion.

dynamic_cast
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
#include <exception>
using namespace std;
class Base { virtual void dummy() {} };
class Derived: public Base { int a; };
int main () {
try {
Base * pba = new Derived;
Base * pbb = new Base;
Derived * pd;
pd = dynamic_cast<Derived*>(pba);
if (pd==0) cout << "Null pointer on first type-cast.\n";
pd = dynamic_cast<Derived*>(pbb);
if (pd==0) cout << "Null pointer on second type-cast.\n";
} catch (exception& e) {cout << "Exception: " << e.what();}
return 0;
}

The output is:

dynamic_cast_output
1
Null pointer on second type-cast.

const_cast <type-id> (expression)

const_cast can set or remove the constness of the object pointed by a pointer. However, it should be noted that actually this type of casting is not designed for modifing the value of a const object, but for faciliting program. For example, if a const pointer needs to pass to a function that expects a non-const argument:

const_cast
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
using namespace std;
void print (char * str)
{
cout << str << '\n';
}
int main () {
const char * c = "sample text";
print ( const_cast<char *> (c) );
return 0;
}

The output is:

const_cast
1
sample text

This example above can work because in function print does not write to the pointer. Note that, it will cause undefined behavior to write to a removing constness of a pointed object.

reinterpret_cast <type-id> (expression)

reinterpret_cast can convert any pointer type to any other pointer type, even of unrelated classes. That means the operation in this conversion is a binary copy only and no check will be performed. reinterpret_cast can also cast pointers to or from integer types. The format in which the integer value represents a pointer is platform-specific. The operations which can be performed by reinterpret_cast but not static_cast are low-level operations based on reinterpreting the binary representations of the type. On most cases, this conversion results in code which is system-specific.

const_cast
1
2
3
4
class A { /* ... */ };
class B { /* ... */ };
A * a = new A;
B * b = reinterpret_cast<B*>(a);