协慌网

登录 贡献 社区

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

有什么用途:

  • 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 风格演员阵容的另一个原因。

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

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

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

使用const_cast来抛弃const/volatile 。除非你使用 const 不正确的 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 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);
}