什么时候应该使用static_cast,dynamic_cast,const_cast和reinterpret_cast?

什么是正确的用途:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C风格演员(type)value
  • 函数式投射type(value)

如何决定在哪些特定情况下使用哪个?

static_cast是您应该尝试使用的第一个演员。 它执行types之间的隐式转换(例如intfloatvoid*指针),还可以调用显式转换函数(或隐式转换函数)。 在很多情况下,明确声明static_cast并不是必须的,但是注意到T(something)语法相当于(T)something并且应该避免(稍后再说)。 一个T(something, something_else)是安全的,然而,保证调用构造函数。

static_cast也可以通过inheritance层次结构进行投射。 向上(向基类)投射是不必要的,但是向下投射时,只要不通过virtualinheritance投射就可以使用。 但是,它并没有检查,而且它是一个未定义的行为,将一个层次结构下的static_cast转换为实际上不是该对象types的types。


const_cast可以用来删除或添加const到一个variables; 没有其他C ++强制转换能够删除它(甚至不reinterpret_cast )。 需要注意的是,如果原始variables是const ,那么修改以前的const值只是未定义的; 如果你使用它来把const引用到没有用const声明的东西,那么它是安全的。 例如,当基于const重载成员函数时,这会很有用。 它也可以用来将const添加到一个对象中,比如调用成员函数的重载。

const_castvolatile上也是类似的,尽pipe这种情况不太常见。


dynamic_cast几乎专门用于处理多态性。 您可以将任何多态types的指针或引用强制转换为任何其他类types(多态types至less具有一个声明或inheritance的虚函数)。 您可以使用它不仅仅是向下投掷 – 您可以侧身投掷,甚至可以投掷另一个链条。 dynamic_cast将找出所需的对象,并在可能的情况下返回。 如果不能,则在指针的情况下它将返回nullptr ,或者在引用的情况下抛出std::bad_cast

dynamic_cast有一些限制。 如果在inheritance层次结构中存在多个相同types的对象(所谓的“可怕钻石”),并且您没有使用virtualinheritance,则不起作用。 它也只能通过公共inheritance – 它总是不能通过protectedprivateinheritance。 然而,这是很less有问题的,因为这种inheritanceforms很less见。


reinterpret_cast是最危险的演员,应该非常谨慎地使用。 它将一种types直接转换为另一种types,比如将值从一个指针转换为另一个指针,或者将指针存储在一个int ,或者存储其他各种令人讨厌的东西。 在很大程度上,唯一保证你得到reinterpret_cast是通常如果你把结果回到原来的types,你会得到完全相同的值(但不是如果中间types比原来的types小)。 reinterpret_cast也有不less转换。 它主要用于奇怪的转换和位操作,如将原始数据stream转换为实际数据或将数据存储在alignment指针的低位中。


C风格转换和函数风格转换分别使用(type)objecttype(object) 。 C风格的转换被定义为以下的第一个成功:

  • const_cast
  • static_cast (尽pipe忽略访问限制)
  • static_cast (见上),然后是const_cast
  • reinterpret_cast
  • reinterpret_cast ,然后是const_cast

因此,在某些情况下,它可以用来替代其他types的cast,但由于能够转化为reinterpret_cast ,所以可能会非常危险,而且当需要显式转换时,后者应该是首选的,除非您确定static_cast会成功或reinterpret_cast将失败。 即使如此,考虑更长,更明确的select。

C风格强制转换在执行static_cast时也会忽略访问控制,这意味着他们有能力执行其他强制转换无法执行的操作。 不过,这主要是一个混乱,而在我看来,这只是避免C风格演员的另一个原因。

使用dynamic_cast在inheritance层次结构中转换指针/引用。

使用static_cast进行普通的types转换。

使用reinterpret_cast进行位模式的低级重新解释。 谨慎使用。

使用const_cast来转换const/volatile 。 避免这种情况,除非你使用常量不正确的API。

(上面已经给出了很多理论和概念上的解释)

以下是我使用static_castdynamic_castconst_castreinterpret_cast时的一些实际示例

(也可以参考这个来理解说明: http : //www.cplusplus.com/doc/tutorial/typecasting/ )

static_cast:

 OnEventData(void* pData) { ...... // pData is a void* pData, // EventData is a structure eg // typedef struct _EventData { // std::string id; // std:: string remote_id; // } EventData; // On Some Situation a void pointer *pData // has been static_casted as // EventData* pointer EventData *evtdata = static_cast<EventData*>(pData); ..... } 

dynamic_cast:

 void DebugLog::OnMessage(Message *msg) { static DebugMsgData *debug; static XYZMsgData *xyz; if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){ // debug message } else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){ // xyz message } else/* if( ... )*/{ // ... } } 

const_cast:

 // *Passwd declared as a const const unsigned char *Passwd // on some situation it require to remove its constness const_cast<unsigned char*>(Passwd) 

reinterpret_cast:

 typedef unsigned short uint16; // Read Bytes returns that 2 bytes got read. bool ByteBuffer::ReadUInt16(uint16& val) { return ReadBytes(reinterpret_cast<char*>(&val), 2); } 

如果你知道一些内部信息可能会有所帮助

的static_cast

  • C ++编译器已经知道如何将诸如float的缩放器types转换为int。 为他们使用static_cast。
  • 通常,在将Atypes转换为Btypes时,static_cast会调用B的构造函数来传递它。如果B没有这样的构造函数,那么你会得到编译时错误。
  • 如果A和B处于inheritance层次结构(或无效状态),则从A*B*总是成功,否则会出现编译错误。
  • 问题 :如果你把基指针指向派生指针,但是如果它不是有效的转换,那么你不会得到错误。 你得到错误的指针,只要你尝试访问派生指针的成员,你会得到段错误。
  • A& B&
  • 陷阱 :从派生到基地或反之亦然创造新的副本! 对于来自C#/ Java的人来说,上面的许多都可能是一个巨大的惊喜。

的dynamic_cast

  • dynamic_cast使用运行时types信息来判断cast是否有效。 例如,如果指针实际上不是派生types,则(Base*)(Derived*)可能会失败。
  • 这意味着,dynamic_cast与static_cast相比非常昂贵!
  • 对于A*B* ,如果强制转换无效,则dynamic_cast将返回nullptr。
  • 对于A& B&如果强制转换无效,则dynamic_cast将抛出bad_castexception。

const_cast会

  • 虽然static_cast可以做non-const来强制它不能以其他方式。 const_cast可以执行两种方法。
  • 一个很好用的例子是遍历一些像set<T>容器,它只返回它的元素作为const,以确保你不会改变它的键。 但是,如果你的意图是修改对象的非关键成员,那么它应该没问题。 你可以使用const_cast去除常量。
  • 另一个例子是当你想要实现T& foo()以及const T& foo() 。 为了避免代码重复,可以使用const_cast从另一个函数返回一个函数的值。
  • 与上面两个强制转换不同的是,运行时开销很大。

reinterpret_cast的

  • 这基本上说,把这些字节在这个内存位置,并认为它是给定的对象。
  • 例如,可以将4个字节的float加载到int的4个字节中,以查看float中的位是怎样的。
  • 显然,如果数据不正确的types,你可能会得到段错误。
  • 这个强制转换没有运行时开销。

这是否回答你的问题?

我从来没有使用reinterpret_cast ,并怀疑是否遇到需要它的情况是不是一个坏devise的气味。 在代码库中,我在dynamic_cast上的工作使用了很多。 与static_cast的不同之处在于, dynamic_cast执行运行时检查哪些可能(更安全),也可能不会(更多开销)是您想要的(请参阅msdn )。

除了到目前为止的其他答案,这里是不明显的例子,其中static_cast是不够的,所以reinterpret_cast是必要的。 假设有一个函数在输出参数中返回指向不同类的对象的指针(它们不共享一个基类)。 这个函数的一个真实的例子是CoCreateInstance() (见最后一个参数,实际上是void** )。 假设你从这个函数请求特定类的对象,所以你事先知道指针的types(你经常为COM对象所做的)。 在这种情况下,您不能使用static_cast将指针指向void**的指针void** :您需要reinterpret_cast<void**>(&yourPointer)

在代码中:

 #include <windows.h> #include <netfw.h> ..... INetFwPolicy2* pNetFwPolicy2 = nullptr; HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), //static_cast<void**>(&pNetFwPolicy2) would give a compile error reinterpret_cast<void**>(&pNetFwPolicy2) ); 

然而, static_cast适用于简单的指针(不是指向指针的指针),所以上面的代码可以用下面的方法重写,以避免reinterpret_cast (以一个额外的variables的价格):

 #include <windows.h> #include <netfw.h> ..... INetFwPolicy2* pNetFwPolicy2 = nullptr; void* tmp = nullptr; HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), &tmp ); pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp);