
David A. answered 10/12/19
Experienced C++ tutor who loves to mentor and pass on my knowledge
Good question :)
In C, there is only one cast:
#include <iostream>
int main(int argc, const char * argv[]) {
float pi = 3.1415;
int floor = (int) pi; // cast pi to an int
std::cout << "pi (float): " << pi << '\n';
std::cout << "pi (int) : " << floor << '\n';
return 0;
}
C casts simply by surrounding the cast type within parenthesis: e.g. (int)
C++ casts is somewhat stricter in its use because it tends to be more type strict than C. The types of casts used in C++ are as follows:
const_cast:
const_cast can be used to remove or add const to a variable. This can be useful if it is necessary to add/remove constness from a variable. This cast is not often used because casting away constness is essentially breaking a covenant which promises something will not change (but does because of the cast). It is necessary from time to time, but should only be used when absolutely necessary.
static_cast
static_cast is used for normal, ordinary type conversion. This is also the cast responsible for implicit type coersion and can also be called explicitly. You should use it in cases like converting float to int or char to int, etc.
dynamic_cast
dynamic_cast is used for handling polymorphism. You only need to use it when you're casting to a derived class. Its purpose is to ensure that the result of the type conversion points to a valid complete object of the destination pointer type. This is exclusively to be used in inheritence when you cast from base class to derived class.
reinterpret_cast
reinterpret_cast is the last choice cast option because it will perform the cast, even if the compiler thinks it's a mistake to perform the cast. This is similar to the C-style cast. It is primarily used for reinterpreting bit patterns and manipulating data using pointer arithmetic with different types involved. Again, use of this cast should be used only when this is the only option.
Example usage:
#include <iostream>
class Base {
public:
virtual void print() {std::cout << "Base() called\n\n";}
};
class Derived1 : public Base {
public:
virtual void print() {std::cout << "Derived1() called\n\n";}
};
class Derived2 : public Base {
public:
virtual void print() {std::cout << "Derived2() called\n\n";}
};
int main(int argc, const char * argv[]) {
// const_cast
//
const int &constNum = 10; // covenant declared that constNum will not change!
// The assignment below generates a compile error:
// Cannot assign to variable 'constNum' with const-qualified type 'const int &'
// constNum += 5; // Error!
// I can cast away the constness though...
//
const_cast<int&>(constNum) += 5;
std::cout << "constant constNum = 10? Wrong! It's now = " << constNum << "\n\n";
// static_cast
//
float pi = 3.1415;
int floor = pi; // implicity calls static_cast
int floor2 = static_cast<int>(pi);
std::cout << "pi: " << pi << '\n';
std::cout << "floor: " << floor << '\n';
std::cout << "pi (int) static_cast: " << floor2 << "\n\n"; // same as implicit conversion above
// dynamic_cast
//
Derived1 d1;
Base *bp = dynamic_cast<Base*>(&d1); // Valid cast
if (bp) {
std::cout << "Valid cast\n";
bp->print();
} else {
std::cout << "Invalid cast\n\n";
}
Derived2 *dp2 = dynamic_cast<Derived2*>(bp); // Invalid cast
if (dp2) {
std::cout << "Valid cast\n";
dp2->print();
} else {
std::cout << "Invalid cast\n\n";
}
// reinterpret_cast
//
char buffer[8]; // 8 byte array of characters
*(reinterpret_cast<int*>(buffer)) = 10; // reinterpret buffer as a container of ints
*(reinterpret_cast<int*>(buffer) + 1) = 20; // reinterpret buffer as a container of ints
std::cout << "The 1st number in buffer: " << *(reinterpret_cast<int*>(buffer)) << '\n';
std::cout << "The 2nd number in buffer: " << *(reinterpret_cast<int*>(buffer) + 1) << '\n';
return 0;
}
Output:
constant constNum = 10? Wrong! It's now = 15
pi: 3.1415
floor: 3
pi (int) static_cast: 3
Valid cast
Derived1() called
Invalid cast
The 1st number in buffer: 10
The 2nd number in buffer: 20