提问



有什么用途:



  • static_cast

  • dynamic_cast

  • const_cast

  • reinterpret_cast

  • C式演员(type)value

  • 功能式演员type(value)



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

最佳参考


static_cast 是您应该尝试使用的第一个演员。它执行类型之间的隐式转换(例如intfloat或指向void*的指针),它也可以调用显式转换函数(或隐式转换函数)。在许多情况下,明确说明static_cast是不必要的,但重要的是要注意T(something)语法等同于(T)something并且应该避免(稍后会更多)。但是,T(something, something_else)是安全的,并保证调用构造函数。


static_cast也可以通过继承层次结构进行转换。在向上向上(向基类)进行向上渲染时是不必要的,但是当向下向下进行时,只要它没有通过virtual继承进行转换就可以使用它。但是,它不进行检查,并且它是未定义的行为static_cast将层次结构下移到一个实际上不是对象类型的类型。





const_cast 可用于删除或添加const到变量;没有其他C ++演员能够删除它(甚至不reinterpret_cast)。重要的是要注意,如果原始变量是const,则仅修改以前的const值是不确定的;如果你用const来引用一些没有用const声明的东西,它是安全的。这在基于const重载成员函数时很有用,它还可以用于向对象添加const,例如调用成员函数重载。


const_castvolatile上也有类似的作用,尽管这种情况不太常见。





dynamic_cast 几乎专门用于处理多态性。您可以将指向任何多态类型的指针或引用转换为任何其他类类型(多态类型至少有一个虚函数,声明或继承)。您可以使用它而不仅仅是向下投射 - 您可以侧向投射甚至向上投射另一条链。 dynamic_cast将寻找所需的物体,并在可能的情况下将其返回。如果它不能,则在指针的情况下返回nullptr,或者在引用的情况下抛出std::bad_cast


dynamic_cast有一些限制。如果在继承层次结构中存在多个相同类型的对象(所谓的可怕的钻石)并且您没有使用virtual继承,则它不起作用。它也只能通过公共继承 - 它总是无法通过protectedprivate继承。然而,这很少是一个问题,因为这种形式的遗传很少见。





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





C风格演员功能风格演员分别使用(type)objecttype(object)进行演员表演。 C样式转换定义为以下第一个成功:



  • const_cast

  • static_cast(虽然忽略访问限制)

  • static_cast(见上文),然后const_cast

  • reinterpret_cast

  • reinterpret_cast,然后const_cast



因此,它可以在某些情况下用作其他演员阵容的替代品,但由于能够转换为reinterpret_cast而非常危险,而后者在需要明确施法时应该是首选,除非你确定static_cast将成功或reinterpret_cast失败。即使这样,也要考虑更长,更明确的选择。


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

其它参考1


使用dynamic_cast转换继承层次结构中的指针/引用。


使用static_cast进行普通类型转换。


使用reinterpret_cast进行位模式的低级重新解释。使用时要格外小心。


使用const_cast去掉const/volatile。除非你使用const不正确的API,否则请避免这种情况。

其它参考2


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


以下是我使用 static_cast dynamic_cast const_cast reinterpret_cast 时的一些实际示例 STRONG>。


(另请参阅此内容以理解解释:http://www.cplusplus.com/doc/tutorial/typecasting/)[91]


static_cast:


OnEventData(void* pData)

{
  ......

  //  pData is a void* pData, 

  //  EventData is a structure e.g. 
  //  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);
}

其它参考3


如果你对内部有点了解,它可能会有所帮助......


的static_cast



  • C ++编译器已经知道如何将scaler类型转换为int。为他们使用static_cast。

  • 通常,在将类型A转换为B时,static_cast会调用B的构造函数传递它A.如果B没有这样的构造函数,那么就会出现编译时错误。

  • A*转换为B*,如果A和B处于继承层次结构(或无效),则总是成功,否则会出现编译错误。

  • Gotcha :如果你将基指针强制转换为派生指针,但如果实际对象不是派生类型,那么你不得到错误。你得到错误的指针和as当您尝试访问派生指针的成员时,您会在运行时获得段错误。

  • 同样适用于A&B&

  • Gotcha :从Derived转换为Base或反之,创建新副本!对于来自C#/Java的人来说,上面的许多内容都会让人大吃一惊。



的dynamic_cast



  • dynamic_cast使用运行时类型信息来确定强制转换是否有效。例如,如果指针实际上不是派生类型,则(Base*)(Derived*)可能会失败。

  • 这意味着,与static_cast相比,dynamic_cast非常昂贵!

  • 对于A*B*,如果强制转换无效,则dynamic_cast将返回nullptr。

  • 对于A&B&如果强制转换无效,则dynamic_cast将抛出bad_cast异常。

  • 与其他演员表不同,存在运行时开销。



的const_cast



  • 虽然static_cast可以对const执行非const,但是它不能反过来.const_cast可以两种方式。

  • 这方面的一个例子是迭代通过像set<T>这样的容器,它只返回它的元素作为const,以确保你不会改变它的键。但是如果你的目的是修改对象的非关键成员那么它应该没问题。您可以使用const_cast删除constness。

  • 另一个例子是你想要实现T& foo()以及const T& foo()。为避免代码重复,您可以应用const_cast从一个函数返回另一个函数的值。



的reinterpret_cast



  • 这基本上表示在这个内存位置取这些字节并将其视为给定对象。

  • 例如,您可以将4个字节的float加载到4个字节的int中,以查看float中的位是什么样的。

  • 显然,如果数据类型不正确,您可能会遇到段错误。

  • 此演员表没有运行时开销。


其它参考4


这是否回答了你的问题?[92]


我从来没有使用reinterpret_cast,并且想知道是否遇到需要它的情况并不是设计糟糕的气味。在我dynamic_cast的代码库中使用了很多。与!]]]]**static_cast dynamic_cast运行时检查可能(更安全)或不可能(更多开销)是你想要的(见msdn)。[93]

其它参考5


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


在代码中:


#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(以额外变量为代价):


#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);