Using named casts is considered a safer and reliable method of type conversion in C++ compared to other methods. In C++, there are four main named type-casting expressions:
static_cast
dynamic_cast
const_cast
reinterpret_cast
C++ static_cast
We use static_cast
for standard type conversions, such as converting from float
to int
.
Let's look at an example.
#include <iostream>
using namespace std;
int main() {
float my_float = 3.14;
// convert float to int
int my_int = static_cast<int>(my_float);
cout << "Float: " << my_float << " -> Int: " << my_int << endl;
return 0;
}
Output
Float: 3.14 -> Int: 3
The static_cast<int>(my_float)
expression converts the float value stored in my_float to an integer and stores it in my_int.
Because floating-point values can have decimal components and integers cannot, this conversion removes the decimal part, converting 3.14 to 3.
C++ dynamic_cast
We mainly use dynamic_cast
for polymorphic type conversions, especially when dealing with inheritance hierarchies. It's typically used in scenarios where a base class pointer needs to be converted to a derived class pointer.
Let's look at an example.
#include <iostream>
using namespace std;
class Base {
public:
// base class print function
virtual void print() {
cout << "Base class" << endl;
}
};
class Derived : public Base {
public:
// derived class print function overriding the base class
void print() override {
cout << "Derived class" << endl;
}
};
int main() {
// create a Base class pointer
// pointing to a Derived object
Base *base_ptr = new Derived();
// use dynamic_cast to cast the
// Base pointer to a Derived pointer
Derived *derived_ptr = dynamic_cast<Derived*>(base_ptr);
// call the print function through the derived pointer
if (derived_ptr) {
derived_ptr->print();
}
// delete the dynamically allocated object
delete base_ptr;
return 0;
}
Output
Derived class
In this example,
- We defined a base class
Base
and a derived classDerived
, whereDerived
inherits fromBase
. - In
main()
, we created a pointerbase_ptr
of typeBase*
pointing to aDerived
object. - We then used
dynamic_cast
to castbase_ptr
to aDerived*
pointer and assign it toderived_ptr
. - Finally, we called the
print()
function throughderived_ptr
, which means that we can access theDerived
class function through theBase
class pointer after the dynamic cast.
Note: If the base class pointer doesn't point to an object of the derived class, dynamic_cast
returns nullptr
.
C++ const_cast
We use const_cast
to cast away the const qualifier from a variable.
One common scenario where we can use const_cast
is when working with third-party libraries that have functions which take non-const pointers as arguments, but we need to pass in const
data.
Let's look at an example.
#include <iostream>
using namespace std;
// function that takes a non-const pointer
void modify_data(int* data) {
// modify the data
*data *= 2;
}
int main() {
int x = 10;
// a const pointer for variable x
const int* ptr = &x;
// use const_cast to
// remove const qualifier and allow modification
int* mutable_ptr = const_cast<int*>(ptr);
// call the function
modify_data(mutable_ptr);
// value is modified successfully
cout << "Modified value: " << x << endl;
return 0;
}
Output
Modified value: 20
In this example, we used the const_cast
expression to remove the const
qualifier from a pointer to pass it through a function that takes non-const pointer as an argument.
Here,
modify_data(int* data)
: is a function that takes non-const pointer as an argument- ptr: is a const pointer that we need to pass to
modify_data
const_cast<int*>(ptr)
: casts ptr as a non-const pointer and assigns it to mutable_ptr
C++ reinterpret_cast
reinterpret_cast
is used to convert one pointer type to another pointer type or one reference type to another reference type.
Unlike static_cast
, reinterpret_cast
doesn't actually convert the data types but reinterprets one pointer type as another at compile time.
Let's look at an example.
#include <iostream>
using namespace std;
int main() {
// create an integer variable
int x = 67;
// pointer to an integer
int* ptr_to_int = &x;
// reinterpret the pointer to an integer
// as a pointer to char
char* ptr_to_char = reinterpret_cast<char*>(ptr_to_int);
// dereference the double pointer
// originally holding an integer as if it contains a double
cout << "Dereferencing ptr_to_char: " << *ptr_to_char << endl;
return 0;
}
Output
Dereferencing ptr_to_char: C
Here, we used reinterpret_cast
to reinterpret the pointer ptr_to_int
, which originally pointed to an integer, as a pointer to a character.
This means that the memory location pointed by ptr_to_int
still holds an integer value. But it will be treated as a character.
Warning: reinterpret_cast
allows for almost any pointer or integer type conversion without any type safety checks. This can result in undefined behavior.
So, reinterpret_cast
should be used with caution.