Casting in C++
C-style casting, static casting, dynamic casting, reinterept casting
C-style casting
1 | int main() { |
1 | 3.5 |
When comparing between signed and unsigned types, unexpected behavior could happen.
1 | int main() { |
1 | x >= y |
The reason is that when comparing x
and y
, they will first be converted to two’s complement representation.
for int x = -1;
, its two’s complement representation is: 1111 1111 1111 1111 1111 1111 1111 1111
.
for unsigned int y = 1;
, its two’s complement representation is: 0000 0000 0000 0000 0000 0000 0000 0001
.
The alternative solution is to use std::cmp_greater
for better safe comparison.
1 | int main() { |
1 | x < y |
Static casting
It is a compile-time cast. In general, static_cast is used to convert between numeric data types (i.e. int to float).
static_cast is not as safe as dynamic_cast as it does no run-time type check.
1 | class Base { |
1 | Base print, x = 1 |
It is okay to cast an object to its base class type, but not the other way.
Continue the above example.
1 | class Base { |
1 | Base print, x = 1 |
To use static_cast
in case of inheritance, the base class must be accessible to the derived classes. In the example above, if Derived
is inherited as private/protected
, it will not compile.
static_cast
is able to cast to and from void pointer
1 | int main() { |
1 | 10 |
Dynamic casting
Definition from cpprefernce: Safely converts pointers and references to classes up, down, and sideways along the inheritance hierarchy..
upcasting and downcasting can be illustrated in the figure below.
dynamic_cast does run-time type check so it will introduce runtime overhead. To work with dynamic_cast, there must be one virtual function in the base class. For example:
1 | class Base { |
1 | main.cpp:32:19: error: 'Base' is not polymorphic |
Reinterpret cast
It is used to convert a pointer of some data type into a pointer of another data type. It does not check if the pointer type and data pointed is same or not.
You will see some unexpected results. For example:
1 | int main() { |
1 | 1078523331 |
Let’s see a more comprehensive example.
1 | struct GameStats { |
1 | 6 |
The memory allocation of buffer can be depicted as follows.
Although C-style casting can work, using reinterpret_cast
is more readable.
Reinterpret_cast can also convert a pointer to a class to another class.
1 | class A { |
1 | in B, m_x = 0 |
References
- https://en.cppreference.com/w/cpp/utility/intcmp
- https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines
- https://learn.microsoft.com/en-us/cpp/cpp/static-cast-operator?view=msvc-170
- https://en.cppreference.com/w/cpp/language/dynamic_cast
- https://www.geeksforgeeks.org/reinterpret_cast-in-c-type-casting-operators/
Casting in C++