这方面的一个例子就是迭代一些像 set<T> 这样的容器,它只返回它作为const的元素,以确保你没有't change its key. However if your intent is to modify object'的非关键成员,那么它应该没问题 . 您可以使用const_cast删除constness .
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.
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 有一些限制 . 它没有't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called '使用 virtual 继承来破坏钻石') and you aren't . 它也只能通过公共继承 - 它总是无法通过 protected 或 private 继承 . 然而,这很少是一个问题,因为这种形式的遗传很少见 .
7 回答
this回答你的问题吗?
我从来没有使用
reinterpret_cast
,并想知道是否遇到需要它的情况并不是一种糟糕的设计气味 . 在代码库中,我在dynamic_cast
上工作了很多 . 与static_cast
的区别在于dynamic_cast
执行运行时检查,可能(更安全)或不可能(更多开销)是您想要的(请参阅msdn) .使用
dynamic_cast
转换继承层次结构中的指针/引用 .使用
static_cast
进行普通类型转换 .使用
reinterpret_cast
进行位模式的低级重新解释 . 使用时要格外小心 .使用
const_cast
删除const/volatile
. 除非你使用const不正确的API,否则请避免这种情况 .如果你对内部有点了解,它可能会有所帮助......
static_cast
C编译器已经知道如何在诸如float之类的scaler类型之间进行转换 . 使用
static_cast
.当你要求编译器从类型
A
转换为B
时,static_cast
调用B
的构造函数将A
作为参数传递 . 或者,A
可以有一个转换运算符(即A::operator B()
) . 如果B
没有这样的构造函数,或者A
没有转换运算符,则会出现编译时错误 .如果A和B在继承层次结构中(或无效),则从
A*
转换为B*
总是成功,否则会出现编译错误 .Gotcha :如果将基指针强制转换为派生指针,但如果实际对象不是真正的派生类型,则不会出现错误 . 你得到错误的指针,很可能在运行时出现段错误 .
A&
到B&
也是如此 .Gotcha :从Derived转换为Base或反之,创建新副本!对于来自C#/ Java的人来说,这可能是一个巨大的惊喜,因为结果基本上是从Derived创建的切断对象 .
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的元素,以确保你没有't change its key. However if your intent is to modify object'的非关键成员,那么它应该没问题 . 您可以使用const_cast删除constness .另一个例子是你想要实现
T& foo()
以及const T& foo()
. 为避免代码重复,可以应用const_cast从一个函数返回另一个函数的值 .reinterpret_cast
这基本上说在这个内存位置取这些字节并将其视为给定对象 .
例如,您可以将4个字节的float加载到4个字节的int中,以查看float中的位是什么样的 .
显然,如果数据类型不正确,您可能会遇到段错误 .
此强制转换没有运行时开销 .
除了到目前为止的其他答案,这里是不明显的例子
static_cast
是不够的,所以需要reinterpret_cast
. 假设有一个函数在输出参数中返回指向不同类的对象(不共享公共基类)的指针 . 这种函数的一个真实例子是CoCreateInstance()(参见最后一个参数,实际上是void**
) . 假设您从此函数请求特定的对象类,因此您事先知道指针的类型(您经常为COM对象执行此操作) . 在这种情况下,您无法使用static_cast
将指针指向void**
指针:您需要reinterpret_cast<void**>(&yourPointer)
.在代码中:
但是,
static_cast
适用于简单指针(不是指针指针),因此可以通过以下方式重写上述代码以避免reinterpret_cast
(以额外变量为代价):虽然其他答案很好地描述了C演员之间的所有差异,但我想补充一个简短的说明,为什么你不应该使用C风格的演员
(Type) var
和Type(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 <>()甚至可以将整数值重新解释为指针 .
这是样本 .
C语言被添加到语言中的主要原因是允许开发人员澄清他的意图 - 为什么他要去做那个演员 . 通过使用在C语言中完全有效的C样式转换,您使代码的可读性降低,并且更容易出错,尤其是对于未创建代码的其他开发人员 . 因此,为了使您的代码更具可读性和显式性,您应该总是喜欢C类型转换而不是C风格的转换 .
以下是Bjarne Stroustrup(C的作者)的书The C Programming Language第4版 - 第302页的简短引用 .
(上面已经给出了很多理论和概念上的解释)
当我使用 static_cast , dynamic_cast , const_cast , reinterpret_cast 时,下面是一些 practical examples .
(也可以参考这个来理解解释:http://www.cplusplus.com/doc/tutorial/typecasting/)
static_cast :
dynamic_cast :
const_cast :
reinterpret_cast :
static_cast 是您应该尝试使用的第一个演员表 . 它执行类型之间的隐式转换(例如
int
到float
或指向void*
的指针),它还可以调用显式转换函数(或隐式转换函数) . 在许多情况下,明确指出static_cast
isn 't necessary, but it'重要的是要注意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_cast
在volatile
上的工作方式也类似,但不太常见 .dynamic_cast 几乎专门用于处理多态 . 您可以将指向任何多态类型的指针或引用转换为任何其他类类型(多态类型至少具有一个虚函数,声明或继承) . 您可以使用它而不仅仅是向下投射 - 您可以侧向投射甚至向上投射另一条链 .
dynamic_cast
将寻找所需的对象并在可能的情况下返回它 . 如果不能,则在指针的情况下返回nullptr
,或者在引用的情况下抛出std::bad_cast
.但是,
dynamic_cast
有一些限制 . 它没有't work if there are multiple objects of the same type in the inheritance hierarchy (the so-called '使用virtual
继承来破坏钻石') and you aren't . 它也只能通过公共继承 - 它总是无法通过protected
或private
继承 . 然而,这很少是一个问题,因为这种形式的遗传很少见 .reinterpret_cast 是最危险的演员,应该非常谨慎地使用 . 它将一种类型直接转换为另一种类型 - 例如将值从一个指针转换为另一个指针,或将指针存储在
int
中,或者存储各种其他令人讨厌的东西 . 很大程度上,使用reinterpret_cast
的唯一保证是,通常如果将结果转换回原始类型,您将获得完全相同的值(但如果中间类型小于原始类型,则为 not ) . 还有许多转换 reinterpret_cast 也无法做到 . 它主要用于特别奇怪的转换和位操作,例如将原始数据流转换为实际数据,或将数据存储在对齐指针的低位中 .C-style cast 和 function-style cast 分别使用
(type)object
或type(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风格演员阵容的另一个原因 .