从C过度到C++,总有些地方会不适应,比如cast。之前一直困惑,为什么有些程序会用xx_cast,明明括号就可以搞定的啊?读完这节,觉今是而昨非了。
1 什么C-Style和C++-Style cast?
C:(type) expression
C++:xxx_cast<type>(expression)
2 有什么区别?
C:很粗鲁,几乎可以在任何类型间相互转换,它在提供便利的同时,也增加了很多不可控性,而后者是我们很忌惮的。另外,我们很难追踪cast在哪里被使用过。
C++:提供4种operators,精确控制4种类型的cast,比如static_cast并不能充当const_cast的角色。
3 C++ Cast Operators
i) static_cast
"static_cast
has basically the same power and meaning as the general-purpose C-style cast. It also has the same kind of restrictions. For example, you can't cast a struct
into an int
or a double
into a pointer using static_cast
any more than you can with a C-style cast. Furthermore, static_cast
can't remove const
ness from an expression, because another new cast, const_cast
, is designed specifically to do that. "
static_cast就像多数的C类型映射,将一种数据类型转换成另一种,它也有同样的限制,比如不能将struct转换成int。另外,正如前面提到的,它也不能去除一个对象的const属性。
ii) const_cast
const_cast
is used to cast away the const
ness or volatile
ness of an expression. By using a const_cast
, you emphasize (to both humans and compilers) that the only thing you want to change through the cast is the const
ness or volatile
ness of something. This meaning is enforced by compilers. If you try to employ const_cast
for anything other than modifying the const
ness or volatile
ness of an expression, your cast will be rejected.
const_cast只能用来去除对象的constness or volatileness,编译器看到这个关键字后就会知道使用者的明确意图。如果你想用const_cast来做其他类型映射的话,就YY了。
Example:
class Widget { ... };
class SpecialWidget: public Widget { ... };
void update(SpecialWidget *psw);
SpecialWidget sw; // sw is a non-const object,
const SpecialWidget& csw = sw; // but csw is a reference to
// it as a const object
update(&csw); // error! can't pass a const SpecialWidget* to a function taking a SpecialWidget*
update(const_cast<SpecialWidget*>(&csw)); // fine, the constness of &csw is explicitly cast away (and csw — and sw — may now be
// changed inside update)
update((SpecialWidget*)&csw); // same as above, but using a
// harder-to-recognize C-style cast
Widget *pw = new SpecialWidget;
update(pw); // error! pw's type is Widget*, but update takes a SpecialWidget*
update(const_cast<SpecialWidget*>(pw)); // error! const_cast can be used only to affect constness or volatileness,
// never to cast down the inheritance hierarch
iii) dynamic_cast
The second specialized type of cast, dynamic_cast
, is used to perform safe casts down or across an inheritance hierarchy. That is, you use dynamic_cast
to cast pointers or references to base class objects into pointers or references to derived or sibling base class objects in such a way that you can determine whether the casts succeeded. Failed casts are indicated by a null pointer (when casting pointers) or an exception (when casting references):
dynamic_cast用于将父类指针转换成子类指针,并返回转换的结果。指针转换失败会返回NULL Pointer,引用转换失败会返回exception.
Example:
Widget *pw;
...
update(dynamic_cast<SpecialWidget*>(pw)); // fine, passes to update a pointer to the SpecialWidget pw points to
// if pw really points to one, otherwise passes the null pointer
void updateViaRef(SpecialWidget& rsw);
updateViaRef(dynamic_cast<SpecialWidget&>(*pw)); // fine, passes to updateViaRef the SpecialWidget pw points to if pw
// really points to one, otherwise throws an exception
iv) reinterpret_cast
The last of the four new casting forms is reinterpret_cast
. This operator is used to perform type conversions whose result is nearly always implementation-defined. As a result, reinterpret_cast
s are rarely portable.
我理解,这应该是可以用户自定义的类型转换操作符,所以它的可移植性不佳。最常用的功能是cast betwwen function pointer types。
Example:
typedef void (*FuncPtr)(); // a FuncPtr is a pointer to a function taking no args and returning void
FuncPtr funcPtrArray[10]; // funcPtrArray is an array of 10 FuncPtrs
int doSomething();
funcPtrArray[0] = &doSomething; // error! type mismatch
funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething); // this compiles
4 Different Compilers
某些编译器可能不支持这类cast operators,这时候为了保持程序的兼容性和一致性,可以定义一些宏来完成大致的功能。另外,我们可以方便地追踪cast的使用情况。
总结:
new cast operators虽然丑了点,但是作用突出。既能方便人类和工具解析它们的含义,又能方便编译器检测诊断casting errors。塞文失马,焉知非福?