More Effective C++:类型转换
转自:http://dev.yesky.com/193/2568193.shtml
仔细想想地位卑贱的类型转换功能(cast),其在程序设计中的地位就象goto语句一样令人鄙视。但是它还不是无法令人忍受,因为当在某些紧要的关头,类型转换还是必需的,这时它是一个必需品。
不过C风格的类型转换并不代表所有的类型转换功能。一来它们过于粗鲁,能允许你在任何类型之间进行转换。不过如果要进行更精确的类型转换,这会是一个优点。在这些类型转换中存在着巨大的不同,例如把一个指向const对象的指针(pointer-to-const-object)转换成指向非const对象的指针(pointer-to-non-const-object)(即一个仅仅去除cosnt的类型转换),把一个指向基类的指针转换成指向子类的指针(即完全改变对象类型)。传统的C风格的类型转换不对上述两种转换进行区分。(这一点也不令人惊讶,因为C风格的类型转换是为C语言设计的,而不是为C++语言设计的)。
二来C风格的类型转换在程序语句中难以识别。在语法上类型转换由圆括号和标识符组成,而这些可以用在C++中的任何地方。这使得回答象这样一个最基本的有关类型转换的问题变得很困难,“在这个程序中是否使用了类型转换?”。这是因为人工阅读很可能忽略了类型转换的语句,而利用象grep的工具程序也不能从语句构成上区分出它们来。
C++通过引进四个新的类型转换操作符克服了C风格类型转换的缺点,这四个操作符是,static_cast, const_cast, dynamic_cast, 和reinterpret_cast。在大多数情况下,对于这些操作符你只需要知道原来你习惯于这样写,(type) expression而现在你总应该这样写: static_cast(expression);例如,假设你想把一个int转换成double,以便让包含int类型变量的表达式产生出浮点数值的结果。如果用C风格的类型转换,你能这样写:
int firstNumber, secondNumber; ... double result = ((double)firstNumber)/secondNumber; |
double result = static_cast(firstNumber)/secondNumber; |
class Widget { ... }; class SpecialWidget: public Widget { ... }; void update(SpecialWidget *psw); SpecialWidget sw; // sw 是一个非const 对象。 const SpecialWidget& csw = sw; // csw 是sw的一个引用 // 它是一个const 对象 update(&csw); // 错误!不能传递一个const SpecialWidget* 变量 // 给一个处理SpecialWidget*类型变量的函数 update(const_cast(&csw)); // 正确,csw的const被显示地转换掉( // csw和sw两个变量值在update //函数中能被更新) update((SpecialWidget*)&csw); // 同上,但用了一个更难识别 //的C风格的类型转换 Widget *pw = new SpecialWidget; update(pw); // 错误!pw的类型是Widget*,但是 // update函数处理的是SpecialWidget*类型 update(const_cast(pw)); // 错误!const_cast仅能被用在影响 // constness or volatileness的地方上。, // 不能用在向继承子类进行类型转换。 |
Widget *pw; ... update(dynamic_cast(pw)); // 正确,传递给update函数一个指针 // 是指向变量类型为SpecialWidget的pw的指针 // 如果pw确实指向一个对象, // 否则传递过去的将使空指针。 void updateViaRef(SpecialWidget& rsw); updateViaRef(dynamic_cast(*pw)); //正确。 传递给updateViaRef函数 // SpecialWidget pw 指针,如果pw // 确实指向了某个对象 // 否则将抛出异常 |
int firstNumber, secondNumber; ... ... double result = dynamic_cast(firstNumber)/secondNumber; // 错误!没有继承关系 const SpecialWidget sw; ... update(dynamic_cast(&sw)); // 错误! dynamic_cast不能转换 // 掉const。 |
typedef void (*FuncPtr)(); // FuncPtr is 一个指向函数 // 的指针,该函数没有参数 // 也返回值类型为void FuncPtr funcPtrArray[10]; // funcPtrArray 是一个能容纳 // 10个FuncPtrs指针的数组 |
int doSomething(); |
funcPtrArray[0] = &doSomething; // 错误!类型不匹配 reinterpret_cast可以让你迫使编译器以你的方法去看待它们: funcPtrArray[0] = // this compiles reinterpret_cast(&doSomething); |
#define static_cast(TYPE,EXPR) ((TYPE)(EXPR)) #define const_cast(TYPE,EXPR) ((TYPE)(EXPR)) #define reinterpret_cast(TYPE,EXPR) ((TYPE)(EXPR)) |
double result = static_cast(double, firstNumber)/secondNumber; update(const_cast(SpecialWidget*, &sw)); funcPtrArray[0] = reinterpret_cast(FuncPtr, &doSomething); |
#define dynamic_cast(TYPE,EXPR) (TYPE)(EXPR) |