Hoodlum1980 (fafa)'s Technological Blog

Languages mainly using and digging: C / CPP, ASM, C#, Python. Other languages:Java.

博客园 首页 新随笔 联系 订阅 管理

            这是我偶然在 http://stackoverflow.com/questions/ 网页上发现的一个问题(类似博客园的博问),问题主要是关于询问应该怎样使用,以及何时使用C++里面的这几种类型转换操作符:static_case, dynamic_cast,以及 reinterpret_cast 。我想这是一个非常典型的问题,因此我就想把这篇帖子转载到我的博客上,也是我第一篇转载的文章。

            这个问题的原文链接是:

            http://stackoverflow.com/questions/332030/when-should-staticcast-dynamiccast-and-reinterpretcast-be-used

            下面是该贴的内容以及最佳答案,我将答案从英文译为中文。原文如下:

 

          When should static_cast, dynamic_cast and reinterpret_cast be used?

=========

Question:

=========

            I am reasonably proficient in C++, but I do not have a lot of experience using the cast operators to convert pointers of one type to another. I am familiar with the risks and benefits of pointer casting, as well as the evils of using C-style casts. What I am looking for is a primer on the proper ways to use the various cast operators in C++.

            我熟悉C++,但是我对于使用类型转换操作符却没有什么经验。如同使用C风格转换一样,我熟悉使用其风险但也享受着它的好处。我想知道正确使用这些C++转换操作符的基本方法。

            What are the proper uses of static_cast, dynamic_cast and reinterpret_cast, and how does one decide which one to use in a specific case?

            怎样恰当使用 static_cast, dynamic_cast, reinterpret_cast,怎样在实际使用中决定到底采用它们中的哪一个呢?


            3,107●4●23 asked Dec 1 at 20:11 eJames

 
            I'm torn between the top two answers. Thank you all for answering. I have chosen coppro's answer because of the detail he goes into regarding static_cast, and because he gives some indication of which should be used in preference to others. – eJames Dec 1 at 20:55

 

==========

Anwser:

==========

static_cast

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 the T(something) syntax is equivalent to (T)something and should be avoided (more on that later). A T(something, something_else) is safe, however, and guaranteed to call the constructor.

static_cast can also cast through inheritance hierarchies. It is unecessary when casting upwards (towards a base class), but when casting downwards it can be used as long as it doesn't cast through virtual inheritance. It does not do checking, however, and it is undefined behavior to static_cast down a hierarchy to a type that isn't actually the type of the object.

 

static_cast 是你应该首先尝试的转换。它用于隐式类型转换(例如从 int 到 float,或者从指针到 void*),也可以用于显示(或隐式)转换函数。在很多情况下,显示的书写 static_cast 并不必要,但是必须注意的是,T(something)的写法和(T)something的写法是等效的,并且应该避免后面这种写法。 T(something, something_else)是安全的,并且会保证调用构造函数。

 

static_cast 也可以用于在类的继承方向上进行转换。向上转换(向父类)是不必要的,当向下转换时可以用于转换到 非 virtual的继承(派生)。static_cast不会做对此转换做检查,但是注意如果试图向并非其子类的对象进行转换,则属于未定义行为。

const_cast

const_cast can be used to remove or add const to a variable; no other C++ cast is capable of this (not even reinterpret_cast). It is important to note that using it is only undefined if the orginial variable is const; if you use it to take the const of 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.

const_cast 用于去除或者添加变量中的const修饰。其他的C++转换则做不了这件事(即使 reinterpret_cast 也不行)。注意只有原始变量是常量时,该转换才是未定义的。如果你把一个const引用转换到不带const修饰,则是安全的。这在重载一些基于const定义的成员函数非常有用。也可以用于给一个对象添加const,例如调用一个重载成员函数时。

const_cast 也可以用在转换 volatile 变量上,尽管很少见。

 

dynamic_cast


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 don't have to use it to cast 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 几乎是多态机制所专用的操作符。你可以把任何 多态类型(至少含有一个虚函数,不管是自身的还是继承而来的) 的指针或引用转换到任意的其他对象类型。dynamic_cast 不仅可以向下转换,还可以横向甚至转向其他分支, 它会尽可能选取出你想要的对象并提供。如果它无法转换,则返回NULL(对指针)或者抛出 std::bad_cast (对引用)。

 

reinterpret_cast


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 an int, 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 same value. Other than that, you're on your own. reinterpret_cast cannot do all sorts of conversions; in fact it is relatively limited. It should almost never be used (even interfacing with C code using void* can be done with static_cast).

reinterpret_cast 是最危险的一种转换,应保守使用。它把一种类型直接转换到另外一个类型,例如把值从一个指针变为另一个,或者把指针存储成 int,以及所有其他事物。使用reinterpret_cast 我们唯一可以得到的保证是,把转换结果再转回原始类型时,它的值将保持不变。此外,则取决与你自己。reinterpret_cast 不能完成所有种类的转换。实际上它相对而言很受限, 我们应该尽可能不使用它(即使和C代码做接口,我们通过static_cast 可以使用 void*)。

 

C casts

A C cast ((type)object or type(object)) is defined as the first of the following which succeeds:

const_cast
static_cast
static_cast, then const_cast
reinterpret_cast
reinterpret_cast, then const_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 static_cast, and the latter should be preferred when explicit casting is needed, unless you are sure static_cast will succeed or reinterpret_cast will fail. Even then, consider the longer, more explicit option.

 

C类型转换 ( (type)object 或 type(object) ) 定义为以下任何一个,假如它能够成功:

const_cast
static_cast
static_cast, then const_cast
reinterpret_cast
reinterpret_cast, then const_cast

所以我们可以在某些场合使用C类型转换来代替那些显示的操作符,但是必须强调的是,它有可能成为 static_cast (而static_cast 应该用于必须进行显示转换的场合) ,这是极端危险的,除非你确信 static_cast 会成功而 reinterpret_cast 会失败。即便如此,为长远考虑,应该明确制定具体的转换操作符。

 

I hope this helps!

希望这些对你有帮助!


link|flag answered Dec 1 at 20:26 coppro 3,107●4●23

----------------------------------------------------------------------
 
  I hope others up-vote this answer - it's the only one that actually describes static_cast in enough detail, specifically the limitations on casting within an inheritance hierarchy. – Earwicker Dec 1 at 20:32
 nice answer mate – litb Dec 1 at 20:35
 Agreed with Earwicker, and +1 from here – jalf Dec 1 at 20:39

 Can you clean up the const_cast section? It is worded confusingly. The last sentence is repeated. Any cast can add const, only const_cast can remove it. The middle section should read more like: "It is undefined behavior to modify a variable defined as const, only possible through use of const_cast" – Greg Rogers Dec 1 at 21:01

 

你可以整理下 const_cast 哪一段吗? 描述的比较混乱。最后一句是重复的。任何转换都可以添加const,但是只有 const_cast 可以去掉const。中间一段似乎更应该理解为:“修改一个声明为const的变量属于未定义行为,只有通过 const_cast 才可以办到”。- Greg Rogers

 
 I would recommend as first option dynamic_cast<> which, of course only works as described above. Whenever you can do dynamic_cast<> it will check that the type is really what you believe. – dribeas Dec 1 at 21:02


===============================================================
static_cast

It is able to do the reverse of what an implicit conversion can do. Meaning: narrow (long -> int), widen (int -> long), base-to-derived, void*-to-T* for example. You can't use it for the stuff that an reversed implicit conversion cannot do. (I.e you cannot cast an int* into int).

用于和隐式转换可用时的反向转换。意味着:向窄(long->int),向宽(int->long),父类到子类,void*到T* 等等。不能用于隐式转换无法完成的反向转换。(例如把int*转换为int)。

dynamic_cast

It is used to cast a base pointer into a derived pointer. If the base pointer doesn't point to an object of the type of the derived, it returns 0.
It is used to cast a base reference into a derived reference. If the reference isn't pointing to an object of the derived, it throws std::bad_cast.
It can be considered the checked cast equivalent to static_cast, in that it checks whether the object pointed to really is of the derived type.

用于把父类指针转换为子类指针,如果实际指向不是子类对象,返回0。
用于把父类引用转换为子类引用,如果实际引用不是子类对象,抛出std::bad_cast。
当检验对象是否确实指向子类类型时,可以认为该检验等效于static_cast。

reinterpret_cast

It is used to cast a pointer type to a wide enough integral type and back to the original pointer type.
It is used to cast between pointer types of incompatible types (int* to double* for example). The result of that mapping is unspecified, but it's possible to do so.

用于把指针类型转换到整形以及转回到指针类型。
用于在不相容的两种对象的指针类型之间进行转换(例如int*到double*)。结果将是无法预料的,但有时可能会这样做。

const_cast

It is used to cast away const or volatile. It is used in the rare cases when you have a originally non-const object, which is pointed to by a pointer-to-const or referenced to by a reference-to-const. Casting away constness is considered evil and should not be done if it can be avoided.

用于去掉 const 或 volatile 的转换。它仅仅在很少的情况下使用,即当你拥有const指针指向或const引用引用的一个非const对象时。去掉const的转换是很“邪恶”的,能不用则不用。


A C-style cast is equivalent to the following C++ style casts. The first cast that succeeds is taken (See 5.4 in the Standard):

C转换和下面首先成功的C++类型转换等效(参见标准的5.4):

const_cast, static_cast, static_cast followed by const_cast, reinterpret_cast, reinterpret_cast followed by const_cast.

link|flag edited Dec 1 at 20:31 answered Dec 1 at 20:24 litb 31.9k●1●41●129
===================================================================================================================
 
  Beautiful answer, litb. It is a close call between yours and coppro's. Thank you! – eJames Dec 1 at 20:52
 thanks eJames. i forgot to mention some important things though, which coppro thought about. so you did actually the right choice i think. have fun :) – litb Dec 2 at 0:00

 
===================================================================================================================
 

Use dynamic_cast for converting pointers/references within an inheritance hierarchy.

Use static_cast for ordinary type conversions.

Use reinterpret_cast for low-level reinterpreting of bit patterns. Use with extreme caution.

Use const_cast for casting away const/volatile. Avoid this unless you are stuck using a const-incorrect API.

   answered Dec 1 at 20:22 Fred Larson 1,783●2●12

使用 dynamic_cast 在一个类继承等级内进行转换。
使用 static_cast 做常规类型转换。
使用 reinterpret_cast 在底层bit模式下做转换。使用时尤其需要小心。
使用 const_cast 去掉const/volatile。除非你需要使用无法接受const的API否则避免使用。

   -- Fred Larson

posted on 2009-05-11 11:48  hoodlum1980  阅读(761)  评论(0编辑  收藏  举报