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

e.James 2211 c++ pointers casting c++-faq

有什么用途:

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • C风格演员 (type)value
  • 功能式演员 type(value)

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

coppro.. 2331

static_cast是你应该尝试使用的第一个演员.它执行诸如类型之间的隐式转换(例如intto float或指向void*)之类的操作,并且它还可以调用显式转换函数(或隐式转换函数).在许多情况下,明确说明static_cast不是必要的,但重要的是要注意T(something)语法是等同于(T)something并且应该避免(稍后将详细介绍).T(something, something_else)但是,A 是安全的,并保证调用构造函数.

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)类似的演员表,并且功能相同.它们被定义为以下第一个成功:

  • const_cast
  • static_cast (虽然忽略了访问限制)
  • static_cast (见上文),然后 const_cast
  • reinterpret_cast
  • reinterpret_cast, 然后 const_cast

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

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

  • 我认为上面缺少的一个重要细节是,与static或reinterpret_cast相比,dynamic_cast具有运行时性能损失.这很重要,例如在实时软件中. (18认同)
  • dynamic_cast仅适用于多态类型.你只需要在转换为派生类时使用它.除非你特别需要dynamic_cast的功能,否则static_cast肯定是第一个选择.一般而言,这不是一些神奇的银弹"类型检查演员". (14认同)
  • *"没有其他C++演员能够删除`const`(甚至不是'reinterpret_cast`)"......真的吗?那么`reinterpret_cast <int*>(reinterpret_cast <uintptr_t>(static_cast <int const*>(0)))`? (5认同)
  • 值得一提的是,在处理API的一组不透明数据类型时,`reinterpret_cast`通常是首选的武器 (4认同)
  • 很棒的答案!一个快速评论:如果你有一个Derived*&to cast into Base*&,则可能需要static_cast来构建层次结构,因为双指针/引用不会自动构建层次结构.两分钟前我遇到过这种(坦白,不常见)的情况.;-) (2认同)

Fred Larson.. 304

使用dynamic_cast一个继承层次内进行转化的指针/引用.

使用static_cast普通类型转换.

使用reinterpret_cast的位模式的低级别重读.使用时要格外小心.

使用const_cast铸造远const/volatile.除非你使用const不正确的API,否则请避免这种情况.


Sumit Arora.. 171

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

下面是我使用static_cast,dynamic_cast,const_cast,reinterpret_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);
}

  • 其他一些答案的理论很好,但仍然令人困惑,在阅读其他答案之后看到这些例子真的让它们都有意义.这是没有例子的,我仍然不确定,但有了它们,我现在肯定其他答案意味着什么. (27认同)
  • @LorenzoBelli当然不是.你试过吗?后者不是有效的C++并阻止编译.`static_cast`仅适用于具有已定义转换的类型,通过继承的可见关系或来自/ void*`的类型.对于其他一切,还有其他演员阵容.允许对任何`char*`类型进行`reinterpret cast`以允许读取任何对象的表示 - 并且该关键字有用的唯一情况之一,而不是实现/未定义行为的猖獗生成器.但这不被视为"正常"转换,因此(通常)非常保守的`static_cast`不允许这样做. (3认同)
  • 当您使用数据库等系统软件时,reinterpret_cast非常常见.大多数情况下,你写它没有什么是存储在页中的数据类型,只是返回一个空指针的想法自己的网页经理.它可以进行更高级别的重新解释演员并将其推断为他们想要的任何东西. (2认同)

Shital Shah.. 67

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

的static_cast

  • C++编译器已经知道如何在诸如float之类的scaler类型之间进行转换.使用static_cast他们.
  • 当你要求编译器从类型转换AB,static_cast调用B的构造函数A作为参数传递.或者,A可以有转换运算符(即A::operator B()).如果B没有这样的构造函数,或者A没有转换运算符,则会出现编译时错误.
  • 从演员A*B*总是会成功,如果A和B是在继承层次结构(或无效),否则你会得到编译错误.
  • 问题:如果你将基指针转换为派生指针,但如果实际对象不是真正的派生类型,那么你不会得到错误.你得到错误的指针,很可能是运行时的段错误.这同样适用于A&B&.
  • Gotcha:从Derived转换为Base或者反之,创建副本!对于来自C#/ Java的人来说,这可能是一个巨大的惊喜,因为结果基本上是从Derived创建的切断对象.

的dynamic_cast

  • dynamic_cast使用运行时类型信息来确定强制转换是否有效.例如,(Base*)(Derived*)如果指针实际上不是派生类型的可能失败.
  • 这意味着,与static_cast相比,dynamic_cast非常昂贵!
  • 对于A*to 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中的位是什么样的.
  • 显然,如果数据类型不正确,您可能会遇到段错误.
  • 此强制转换没有运行时开销.


andreas buyk.. 12

请问这个回答你的问题?

我从来没有使用过reinterpret_cast,并且想知道是否遇到需要它的情况并不是一种糟糕的设计气味.在我工作的代码库dynamic_cast中使用了很多.与之不同的 static_castdynamic_cast运行时检查可能(更安全)或不可能(更多开销)是您想要的(参见msdn).

  • 我已经将reintrepret_cast用于一个目的 - 将比特从一个双重中获取(在我的平台上使用相同的大小). (3认同)
  • 需要reinterpret_cast,例如用于处理COM对象.CoCreateInstance()具有void**(最后一个参数)类型的输出参数,您将在其中传递声明为"INetFwPolicy2*pNetFwPolicy2"的指针.为此,您需要编写类似reinterpret_cast <void**>(&pNetFwPolicy2)的内容. (2认同)

Serge Rogatc.. 12

除了到目前为止的其他答案,这里是不明显的例子,其中static_cast不足以满足reinterpret_cast需要.假设有一个函数在输出参数中返回指向不同类的对象(不共享公共基类)的指针.这种函数的一个真实例子是CoCreateInstance()(参见最后一个参数,实际上是这个参数void**).假设您从此函数请求特定的对象类,因此您事先知道指针的类型(您经常为COM对象执行此操作).在这种情况下,你可以不投指针鼠标指针变成void**static_cast:你需要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以下方式重写上述代码以避免(以额外变量为代价):

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


Timmy_A.. 6

而其他的答案很好地描述C++强制转换之间的所有差异,我想补充一个简短的说明,为什么你不应该使用C-风格的转换(Type) varType(var).

对于C++初学者来说,C风格的强制转换看起来就像是对C++强制转换的超集操作(static_cast <>(),dynamic_cast <>(),const_cast <>(),reinterpret_cast <>())而且有人可能比C++强制转换更喜欢它们.事实上,C风格的演员阵容是超集,写作也更短.

C风格演员表的主要问题是它们隐藏了演员的真实意图.C样式的强制类型可以执行几乎所有类型的强制转换,从static_cast <>()和dynamic_cast <>()完成的常规安全强制转换到const_cast <>()等潜在危险的强制转换,其中const修饰符可以被删除,因此const变量可以修改和reinterpret_cast <>(),甚至可以将整数值重新解释为指针.

这是样本.

int a=rand(); // Random number.

int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation.

int* pa2=static_cast<int*>(a); // Compiler error.
int* pa3=dynamic_cast<int*>(a); // Compiler error.

int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo.

*pa4=5; // Program crashes.

C++强制转换被添加到语言中的主要原因是允许开发人员澄清他的意图 - 为什么他要做那个演员.通过使用在C++中完全有效的C样式转换,您可以使代码更不易读,更容易出错,特别是对于那些没有创建代码的开发人员.因此,为了使您的代码更具可读性和显式性,您应该总是更喜欢C++强制转换而不是C风格的强制转换.

以下是Bjarne Stroustrup(C++的作者)一书的简短引用,该书出自The C++ Programming Language第4版 - 第302页.

这种C风格的转换比命名的转换运算符危险得多,因为在大型程序中更难以发现符号,并且程序员想要的转换类型并不明确.


归档时间:

查看次数:

478617 次

最近记录:

9 月 前