Type Casting
Learned in CS247.
Casting allows us to take one type and treat it as another.
In C:
This is dangerous, generally avoid casting unless necessary, subverts type system.
If necessary, use one of the 4 C++ casts instead of C-style casting:
static_cast
- “well-defined” conversions between two typesreinterpret_cast
- allows for poorly defined implementation-dependent castsconst_cast
- “remove” constnessdynamic_cast
- used for safely casting between pointers/references in an inheritance hierarchy
1) static_cast
static_cast
allows for “well-defined” conversions between two types.
g
callsint
version ofg
Another example:
- “trust me bro, I know it’s a Text”
- Undefined behavior if it’s not actually pointing at a
Text
What counts as "well-defined"?
Well-defined conversions in C++ using static_cast
include:
- Conversion between numeric types (e.g., from int to float).
- Conversion from pointer-to-base to pointer-to-derived (upcasting).
- Conversion between explicitly convertible types (using conversion constructors or operator overloads).
- Conversion from Void Pointers to any pointer type.
- Conversion between Enum (C++)s and Integral Types.
I asked for a counter example that clearly illustrates that static_cast
is better than the c-style casting
2) reinterpret_cast
reinterpret_cast
allows for poorly defined implementation dependent casts. Most uses of reinterpret_cast
are undefined behavior.
Why use
reinterpret_cast
?Rarely a use case for it, you should probably use
static_cast
. StackOverflow.”
reinterpret_cast
 only guarantees that if you cast a pointer to a different type, and thenÂreinterpret_cast
 it back to the original type, you get the original value.”
Example from Ross Evans code:
3) const_cast
const_cast
is the only type of cast that can “remove” constness.
Example: using some library that gives us:
Let’s say we know g
doesn’t modify the int
pointed to by p
in any way. Also, I have a const int*
I’d like to call g
with. Compiler will prevent us from calling g
, because it might modify p
.
I can use const_cast
to call g
in the following way:
Generally, const_cast
should be avoided.
Another example, working on legacy codebase that doesn’t use const anywhere. We want to add const
s, make our program const-correct.
Why use
const_cast
?The main problem that
const_cast
fixes is const-poisoning: addingconst
in one location often means we must add it to other locations to allow it to continue to compile.We can use
const_cast
to bridge between const-correct and non-const-correct parts of our program. Make small independent parts of the program const-correct, use const-cast to allow the program to compile as the work is done.
What would happen if g
actually modifies p
? Then, it will end up modifying p
. The compiler will not complain.
Important
the type in a
const_cast
must be a pointer, reference, or pointer to member to an object typeC/C++(717).
4) dynamic_cast
dynamic_cast
is used for safely casting between pointers/references in an inheritance hierarchy
Only safe if pb
actually points to a Text
.
Instead,
- If the cast succeeds (i.e. dynamic type is
Text
), thenpt
points at theText
. Otherwise,pt
is set tonullptr
.
Also can be used on references:
- What if
br
is actually referencing aComic
? Cannot set it to null, since there is no such thing as a null reference. - If
dynamic_cast
fails with a reference: throw astd::bad_cast
exception.
When to use
dynamic_cast
?More often than not,
dynamic_cast
is WRONG. You should rather be trying to leverage Polymorphism (more below). StackOverflow
static_cast
vs dynamic_cast
:
- The use of
dynamic_cast
is safer as it performs a runtime check to ensure that the downcast is valid, returning a null pointer if the downcast fails. Withstatic_cast
, there is no runtime check, so improper downcasting may lead to undefined behavior. Therefore, care must be taken when downcasting, especially when usingstatic_cast
.
Virtual Method
dynamic_cast
only works if you have at least one virtual method. Why? To enable Dynamic Dispatching, so a vptr and vtable is created, and thus help us determine the dynamic type of the object.
Smart Pointer version of Casts
There exist smart pointer versions of each of these casts:
Cast shared_ptrs
to other shared_ptrs
.
Those allow us to make decisions based on Run-Time Type Information (RTTI):
BAD
The above function is poor Object-Oriented Design (because violates polymorphism and Open-Closed Principle). Either use simple Polymorphism within derived classes with Function Overriding, or use the Visitor Pattern if you want to write a method that depends on Polymorphic Types.
Something like this is better
Recall: polymorphic assignment problem. We considered making operator=
virtual.
- operator= non-virtual: partial assignment
- operator= virtual: mixed assignment
Let’s make operator=
virtual in Book
.