static_cast
is used for cases where you basically want to reverse an implicit conversion, with a few restrictions and additions. static_cast
performs no runtime checks. This should be used if you know that you refer to an object of a specific type, and thus a check would be unnecessary. Example:
void func(void *data) {
// conversion from MyClass* -> void* is implicit
MyClass *c = static_cast<MyClass*>(data);
...
}
int main() {
MyClass c;
start_thread(&func, &c) // func(&c) will be called
.join();
}
In this example, you know that you passed a MyClass
object, and thus there is no need for a runtime check to ensure this.
dynamic_cast
dynamic_cast
is used for cases where you don't know what the dynamic type of the object is. You cannot use dynamic_cast
if you downcast and the argument type is not polymorphic. An example
if(JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
...
} else if(ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
...
}
dynamic_cast
returns a null pointer if the object referred to doesn't contain the type casted to as a base class (when you cast to a reference, a bad_cast
exception is thrown in that case).
The following code is not valid, because Base
is not polymorphic (doesn't contain a virtual function):
struct Base { };
struct Derived : Base { };
int main() {
Derived d; Base *b = &d;
dynamic_cast<Derived*>(b); // invalid
}
An "up-cast" is always valid with both static_cast
and dynamic_cast
, and also without any cast, as an "up-cast" is an implicit conversion.
Regular Cast
These casts are also called c-style cast. A c-style cast is basically identical to trying out a range of sequences of C++ casts, and taking the first c++ cast that works, without ever consideringdynamic_cast
. Needless to say that this is much more powerful as it combines all of const_cast
,static_cast
and reinterpret_cast
, but it's also unsafe because it does not usedynamic_cast
.
In addition, C-style casts not only allow you to do this, but also allow you to safely cast to a private base-class, while the "equivalent" static_cast
sequence would give you a compile time error for that.
Some people prefer c-style casts because of their brevity. I use them for numeric casts only, and use the appropriate C++ casts when user defined types are involved, as they provide stricter checking.
const_cast
const_cast(expression) The const_cast<>() is used to add/remove const(ness) (or volatile-ness) of a variable.
static_cast
static_cast(expression) The static_cast<>() is used to cast between the integer types. 'e.g.' char->long, int->short etc.
Static cast is also used to cast pointers to related types, for example casting void* to the appropriate type.
dynamic_cast
Dynamic cast is used to convert pointers and references at run-time, generally for the purpose of casting a pointer or reference up or down an inheritance chain (inheritance hierarchy).
dynamic_cast(expression)
The target type must be a pointer or reference type, and the expression must evaluate to a pointer or reference. Dynamic cast works only when the type of object to which the expression refers is compatible with the target type and the base class has at least one virtual member function. If not, and the type of expression being cast is a pointer, NULL is returned, if a dynamic cast on a reference fails, a bad_cast exception is thrown. When it doesn't fail, dynamic cast returns a pointer or reference of the target type to the object to which expression referred.
reinterpret_cast
Reinterpret cast simply casts one type bitwise to another. Any pointer or integral type can be casted to any other with reinterpret cast, easily allowing for misuse. For instance, with reinterpret cast one might, unsafely, cast an integer pointer to a string pointer.
Whenever you use a cast, you’re breaking the type system. [25] You’re telling the compiler that even though you know an object is a certain type, you’re going to pretend it is a different type. This is an inherently dangerous activity, and a clear source of errors.
Unfortunately, each cast is different: the name of the pretender type surrounded by parentheses. So if you are given a piece of code that isn’t working correctly and you know you want to examine all casts to see if they’re the source of the errors, how can you guarantee that you find all the casts? In a C program, you can’t. For one thing, the C compiler doesn’t always require a cast (it’s possible to assign dissimilar types through a void pointer without being forced to use a cast), and the casts all look different, so you can’t know if you’ve searched for every one.
To solve this problem, C++ provides a consistent casting syntax using four reserved words: dynamic_cast (the subject of the first part of this chapter), const_cast, static_cast, and reinterpret_cast. This window of opportunity opened up when the need fordynamic_cast arose – the meaning of the existing cast syntax was already far too overloaded to support any additional functionality.
By using these casts instead of the (newtype) syntax, you can easily search for all the casts in any program. To support existing code, most compilers have various levels of error/warning generation that can be turned on and off. But if you turn on full errors for the explicit cast syntax, you can be guaranteed that you’ll find all the places in your project where casts occur, which will make bug-hunting much easier.
The following table describes the different forms of casting:
static_cast |
For “well-behaved” and “reasonably well-behaved” casts, including things you might now do without a cast (e.g., an upcast or automatic type conversion). |
const_cast |
To cast away const and/or volatile. |
dynamic_cast |
For type-safe downcasting (described earlier in the chapter). |
reinterpret_cast |
To cast to a completely different meaning. The key is that you’ll need to cast back to the original type to use it safely. The type you cast to is typically used only for bit twiddling or some other mysterious purpose. This is the most dangerous of all the casts. |
The three explicit casts will be described more completely in the following sections.