πŸ’ΌType Casting in C++ 2023

Type casting in C++ allows you to convert a value from one data type to another.

There are several types of casts:

  • Explicit casting: Using C-style casts (int)var

  • Functional casts: std::function<NewType>(var)

  • Static casts: std::static_cast<NewType>(var)

  • Reinterpret casts: std::reinterpret_cast<NewType>(var)

  • Const casts: std::const_cast<NewType>(var)

  • Dynamic casts: std::dynamic_cast<NewType>(var)

Among these:

  • Static casts are used for safer casts that can be checked at compile-time

  • Reinterpret casts do a raw conversion, disregarding type safety

  • Const casts remove const qualifiers

  • Dynamic casts use RTTI to cast to a base or derived type at runtime

When casting:

  • The value is converted from its original type to the new type

  • Data can be lost if the new type has a smaller size

  • Constructors are not called - the raw bytes are reinterpreted

So in general, use the most specific cast that fulfills your requirements. More specific casts like static_cast are safer than reinterpret_cast. And avoid const_cast when possible.

Hope this high-level explanation of type casting in C++ helps!

std::static_cast

std::static_cast performs a cast that can be checked at compile-time for type safety. It should be used for safe and proper conversions between types.

For example:

int x = 10;
double y = std::static_cast<double>(x);

Here we cast an int to a double, which is a safe conversion. The compiler can check this cast.

std::static_cast can perform the following casts:

  • Integral types to other integral types

  • Pointer to pointer

  • Pointer to integral

  • Reference to reference

  • Reference to integral

  • Derived class to base class

  • Base class to derived class (if we know the object is actually a derived class)

For example:

Base* b = new Derived();

Derived* d = std::static_cast<Derived*>(b);  // Ok, we know b points to a Derived

So in summary, std::static_cast performs type-safe casts that can be checked by the compiler. It should be preferred over C-style casts or reinterpret_cast whenever possible.

Hope this explanation helps! Let me know if you have any other questions.

std::reinterpret_cast

Reinterpret casts perform a raw conversion between types, without performing any type checking. They should be used with caution.

For example:

int x = 10;
double* y = reinterpret_cast<double*>(&x);

Here we cast the address of an int to a double* pointer. This is not a proper cast, but a raw reinterpretation of the integer's bytes as a double.

std::reinterpret_cast can cast between any types, even those that would normally be disallowed:

  • Integral to pointer

  • Pointer to integral

  • Unsigned to signed and vice versa

  • Derived to base (or reverse) without regard to object's actual type

For example:

Base* b = new Derived();

Base* b2 = reinterpret_cast<Base*>(b);  // Ok but unsafe!

Here we cast a Derived pointer to a Base pointer, without checking if the object is actually a Derived.

In summary, reinterpret_cast performs an unsafe raw conversion between types, disregarding type safety.

It should only be used when absolutely necessary, as it can easily lead to undefined behavior and bugs.

Hope this explanation helps!

std::const_cast

std::const_cast performs a cast that removes any const qualifiers from a type. This allows modifying a const object.

For example:

const int x = 10;

int* y = const_cast<int*>(&x);

*y = 20; // Modifies a 'const int' - undefined behavior!

Here we:

  • Define a const int

  • Cast away the constness using const_cast<int*>

  • This gives us a non-const pointer to a const object

  • When we modify this pointer, we modify a const object - causing undefined behavior.

const_cast can cast:

  • Pointer-to-const to pointer

  • Reference-to-const to reference

  • Const type to non-const type

In essence, it performs a const_cast on the type.

const_cast should be used with extreme caution, as modifying const objects leads to undefined behavior.

It is best to avoid the need for const_cast whenever possible, by using const correctly.

In summary, const_cast casts away const qualifiers from a type. But it does not actually make a const object non-const - it simply tricks the compiler. Modifying the resulting non-const reference or pointer to a const object is undefined.

Hope this explanation helps!

std::dynamic_cast

std::dynamic_cast performs a cast at run-time using RTTI. It can cast between related types, even unrelated types that have a conversion.

For example:

class Animal {};
class Dog : public Animal {};

Animal* a = new Dog();

Dog* d = dynamic_cast<Dog*>(a);  // OK, points to Dog object

Here we:

  • Create a Dog object pointed to by an Animal pointer

  • Cast to a Dog pointer using dynamic_cast

  • The cast succeeds at runtime because the object is actually a Dog

This works because:

  • dynamic_cast uses RTTI to determine the actual type at runtime

  • It can only cast between related types in an inheritance hierarchy

Advantages over static_cast:

  • Can cast between unrelated types with a conversion function

  • Returns nullptr if cast fails, rather than causing undefined behavior

So in summary, dynamic_cast performs a safe run-time cast using RTTI. It checks if the cast is valid, and only performs it if so.

This allows casting between related types, even when the exact type is unknown at compile-time.

Hope this explanation helps! Let me know if you have any other questions regarding type casting in C++.

Last updated