转载自:
Regular cast vs. static_cast vs. dynamic_cast
标签1
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.
标签2
Examples
If we have the following classes
class B {};
class D : B {};
then you can do the following
B* b = new D();
D* d1 = static_cast<D*>b; // Valid! d1 is a valid and correct pointer to a D
D* d2 = dynamic_cast<D*>b; // Valid! d2 is a valid and correct pointer to a D
In this example both pointers d1 and d2 will point to a correct typed version of b
The problem comes in the following example:
B* b = new B();
D* d1 = static_cast<D*>b; // Invalid!
D* d2 = dynamic_cast<D*>b; // Valid, but d2 is now a null pointer
Now d1 will point to a data segment of type D*, but the actual data is B*, and will lead to memory issues and corruption. d2 on the other hand will be a null pointer and can be checked for and handled correctly.
Because dynamic_cast performs runtime type checking it is also slower.
EDIT:
Since dynamic_cast can incurr extra runtime, it can be turned off by instructing the compiler not to include Runtime Type Information.
There are also other cast operators.
Reinterpret Cast
This is the ultimate cast, which disregards all kind of type safety, allowing you to cast anything to anything else, basically reassigning the type information of the bit pattern.
int i = 12345;
MyClass* p = reinterpret_cast<MyClass*> i;
It is very dangerous unless you know what you are doing, and is basically the equivilant of C-cast. Like so;
int i = 0;
void *v = 0;
int c = (int)v; // is valid
int d = static_cast<int>(v); // is not valid, different types
int e = reinterpret_cast<int>(v); // is valid, but very dangerous
And then we have the const_cast<> which removes the const-ness of a variable.
标签3
When should static_cast, dynamic_cast and reinterpret_cast be used?
static_cast is the first cast you should attempt to use. It does things like implicit conversions between types (such as int to float, or pointer to void*), and it can also call explicit conversion functions (or implicit ones). In many cases, explicitly stating static_cast isn't necessary, but it's important to note that theT(something) syntax is equivalent to (T)something and should be avoided (more on that later). AT(something, something_else) is safe, however, and guaranteed to call the constructor.
static_cast can also cast through inheritance hierarchies. It is unnecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast throughvirtual inheritance. It does not do checking, however, and it is undefined behavior to static_castdown a hierarchy to a type that isn't actually the type of the object.
const_cast can be used to remove or add const to a variable; no other C++ cast is capable of removing it (not even reinterpret_cast). It is important to note that modifying a formerly constvalue is only undefined if the original variable is const; if you use it to take the const off a reference to something that wasn't declared with const, it is safe. This can be useful when overloading member functions based on const, for instance. It can also be used to add const to an object, such as to call a member function overload.
const_cast also works similarly on volatile, though that's less common.
dynamic_cast is almost exclusively used for handling polymorphism. You can cast a pointer or reference to any polymorphic type to any other class type (a polymorphic type has at least one virtual function, declared or inherited). You can use it for more than just casting downwards -- you can cast sideways or even up another chain. The dynamic_cast will seek out the desired object and return it if possible. If it can't, it will return NULL in the case of a pointer, or throw std::bad_cast in the case of a reference.
dynamic_cast has some limitations, though. It doesn't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called 'dreaded diamond') and you aren't using virtualinheritance. It also can only go through public inheritance - it will always fail to travel throughprotected or private inheritance. This is rarely an issue, however, as such forms of inheritance are rare.
reinterpret_cast is the most dangerous cast, and should be used very sparingly. It turns one type directly into another - such as casting the value from one pointer to another, or storing a pointer in anint, or all sorts of other nasty things. Largely, the only guarantee you get with reinterpret_cast is that if you cast the result back to the original type, you will get the exact same value. There are a number of conversions that reinterpret_cast cannot do, too. It's used primarily for particularly weird conversions and bit manipulations, like turning a raw data stream into actual data, or storing data in the low bits of an aligned pointer.
C casts are casts using (type)object or type(object). A C-style cast is defined as the first of the following which succeeds:
-
const_cast -
static_cast -
static_cast, thenconst_cast -
reinterpret_cast -
reinterpret_cast, thenconst_cast
It can therefore be used as a replacement for other casts in some instances, but can be extremely dangerous because of the ability to devolve into a reinterpret_cast, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast will succeed orreinterpret_cast will fail. Even then, consider the longer, more explicit option.
C-style casts also ignore access control when performing a static_cast, which means that they have the ability to perform an operation that no other cast can. This is mostly a kludge, though, and in my mind is just another reason to avoid C-style casts.
本文详细解释了C++中static_cast、dynamic_cast和reinterpret_cast等类型的使用场景与区别。通过具体例子展示了不同转换方式的特点及潜在风险,并给出了推荐的使用实践。

被折叠的 条评论
为什么被折叠?



