[转]C++的类型转换符:static_cast、const_case、dynamic_cast

dynamic_cast:通常在基类和派生类之间转换,使用到RTTI(Runtime Type Information)在运行时判断转换是否正确,如不正确将抛出异常。 
const_cast:主要针对const和volatile的转换.   
static_cast:一般用于基本数据类型之间的转换转换,no run-time check,编译时判断。 

reinterpret_cast:用于进行没有任何关联类型之间的转换,比如一个字符指针转换为一个整形数。

C++通过引进四个新的类型转换操作符克服了C风格类型转换的缺点,这四个操作符是,   static_cast,   const_cast,   dynamic_cast,   和reinterpret_cast。在大多数情况下,对于这些操作符你只需要知道原来你习惯于这样写, 
(type)   expression 
而现在你总应该这样写: 
static_cast <type> (expression) 
例如,假设你想把一个int转换成double,以便让包含int类型变量的表达式产生出浮点数值的结果。如果用C风格的类型转换,你能这样写: 
int   firstNumber,   secondNumber; 
... 
double   result   =   ((double)firstNumber)/secondNumber; 
如果用上述新的类型转换方法,你应该这样写: 
double   result   =   static_cast <double> (firstNumber)/secondNumber; 
这样的类型转换不论是对人工还是对程序都很容易识别。 
static_cast在功能上基本上与C风格的类型转换一样强大,含义也一样。它也有功能上限制。例如,你不能用static_cast象用C风格的类型转换一样把struct转换成int类型或者把double类型转换成指针类型,另外,static_cast不能从表达式中去除const属性,因为另一个新的类型转换操作符const_cast有这样的功能。 
其它新的C++类型转换操作符被用在需要更多限制的地方。const_cast用于类型转换掉表达式的const或volatileness属性。通过使用const_cast,你向人们和编译器强调你通过类型转换想做的只是改变一些东西的constness或者   volatileness属性。这个含义被编译器所约束。如果你试图使用const_cast来完成修改constness   或者volatileness属性之外的事情,你的类型转换将被拒绝。下面是一些例子: 
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 <SpecialWidget*> (&csw)); 
//   正确,csw的const被显示地转换掉( 
//   csw和sw两个变量值在update 
//函数中能被更新)   
update((SpecialWidget*)&csw); 
                                                  //   同上,但用了一个更难识别 
                                                  //的C风格的类型转换 
Widget   *pw   =   new   SpecialWidget;   
update(pw);                   //   错误!pw的类型是Widget*,但是 
                                        //   update函数处理的是SpecialWidget*类型   
update(const_cast <SpecialWidget*> (pw)); 
                                        //   错误!const_cast仅能被用在影响 
                                        //   constness   or   volatileness的地方上。, 
                                        //   不能用在向继承子类进行类型转换。 
到目前为止,const_cast最普通的用途就是转换掉对象的const属性。 
对我有用[0]丢个板砖[0]引用举报管理TOP


第二种特殊的类型转换符是dynamic_cast,它被用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用dynamic_cast把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,而且你能知道转换是否成功。失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时): 
Widget   *pw; 
... 
update(dynamic_cast <SpecialWidget*> (pw)); 
//   正确,传递给update函数一个指针 
//   是指向变量类型为SpecialWidget的pw的指针 
//   如果pw确实指向一个对象, 
//   否则传递过去的将使空指针。 
void   updateViaRef(SpecialWidget&   rsw); 
updateViaRef(dynamic_cast <SpecialWidget&> (*pw)); 
                                                  //正确。   传递给updateViaRef函数 
                                                  //   SpecialWidget   pw   指针,如果pw   
                                                  //   确实指向了某个对象 
                                                  //   否则将抛出异常 
dynamic_casts在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上(参见条款M24),也不能用它来转换掉constness: 
int   firstNumber,   secondNumber; 
... 
double   result   =   dynamic_cast <double> (firstNumber)/secondNumber; 
                                                  //   错误!没有继承关系 
const   SpecialWidget   sw; 
... 
update(dynamic_cast <SpecialWidget*> (&sw)); 
                                                  //   错误!   dynamic_cast不能转换 
                                                  //   掉const。 
如你想在没有继承关系的类型中进行转换,你可能想到static_cast。如果是为了去除const,你总得用const_cast。




第二种特殊的类型转换符是dynamic_cast,它被用于安全地沿着类的继承关系向下进行类型转换。这就是说,你能用dynamic_cast把指向基类的指针或引用转换成指向其派生类或其兄弟类的指针或引用,而且你能知道转换是否成功。失败的转换将返回空指针(当对指针进行类型转换时)或者抛出异常(当对引用进行类型转换时): 
Widget   *pw; 
... 
update(dynamic_cast <SpecialWidget*> (pw)); 
//   正确,传递给update函数一个指针 
//   是指向变量类型为SpecialWidget的pw的指针 
//   如果pw确实指向一个对象, 
//   否则传递过去的将使空指针。 
void   updateViaRef(SpecialWidget&   rsw); 
updateViaRef(dynamic_cast <SpecialWidget&> (*pw)); 
                                                  //正确。   传递给updateViaRef函数 
                                                  //   SpecialWidget   pw   指针,如果pw   
                                                  //   确实指向了某个对象 
                                                  //   否则将抛出异常 
dynamic_casts在帮助你浏览继承层次上是有限制的。它不能被用于缺乏虚函数的类型上(参见条款M24),也不能用它来转换掉constness: 
int   firstNumber,   secondNumber; 
... 
double   result   =   dynamic_cast <double> (firstNumber)/secondNumber; 
                                                  //   错误!没有继承关系 
const   SpecialWidget   sw; 
... 
update(dynamic_cast <SpecialWidget*> (&sw)); 
                                                  //   错误!   dynamic_cast不能转换 
                                                  //   掉const。 
如你想在没有继承关系的类型中进行转换,你可能想到static_cast。如果是为了去除const,你总得用const_cast。




这四个类型转换符中的最后一个是reinterpret_cast。使用这个操作符的类型转换,其的转换结果几乎都是执行期定义(implementation-defined)。因此,使用reinterpret_casts的代码很难移植。 
reinterpret_casts的最普通的用途就是在函数指针类型之间进行转换。例如,假设你有一个函数指针数组: 
typedef   void   (*FuncPtr)();             //   FuncPtr   is   一个指向函数 
                                                                //   的指针,该函数没有参数 
//   返回值类型为void 
FuncPtr   funcPtrArray[10];               //   funcPtrArray   是一个能容纳 
                                                                //   10个FuncPtrs指针的数组 
让我们假设你希望(因为某些莫名其妙的原因)把一个指向下面函数的指针存入funcPtrArray数组: 
int   doSomething(); 
你不能不经过类型转换而直接去做,因为doSomething函数对于funcPtrArray数组来说有一个错误的类型。在FuncPtrArray数组里的函数返回值是void类型,而doSomething函数返回值是int类型。 
funcPtrArray[0]   =   &doSomething;           //   错误!类型不匹配   
reinterpret_cast可以让你迫使编译器以你的方法去看待它们: 
funcPtrArray[0]   =                                       //   this   compiles 
    reinterpret_cast <FuncPtr> (&doSomething); 
转换函数指针的代码是不可移植的(C++不保证所有的函数指针都被用一样的方法表示),在一些情况下这样的转换会产生不正确的结果(参见条款M31),所以你应该避免转换函数指针类型,除非你处于着背水一战和尖刀架喉的危急时刻。一把锋利的刀。一把非常锋利的刀。 
如果你使用的编译器缺乏对新的类型转换方式的支持,你可以用传统的类型转换方法代替static_cast,   const_cast,   以及reinterpret_cast。也可以用下面的宏替换来模拟新的类型转换语法: 
#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); 
这些模拟不会象真实的操作符一样安全,但是当你的编译器可以支持新的的类型转换时,它们可以简化你把代码升级的过程。 
没有一个容易的方法来模拟dynamic_cast的操作,但是很多函数库提供了函数,安全地在派生类与基类之间进行类型转换。如果你没有这些函数而你有必须进行这样的类型转换,你也可以回到C风格的类型转换方法上,但是这样的话你将不能获知类型转换是否失败。当然,你也可以定义一个宏来模拟dynamic_cast的功能,就象模拟其它的类型转换一样: 
#define   dynamic_cast(TYPE,EXPR)           (TYPE)(EXPR) 
请记住,这个模拟并不能完全实现dynamic_cast的功能,它没有办法知道转换是否失败。 
我知道,是的,我知道,新的类型转换操作符不是很美观而且用键盘键入也很麻烦。如果你发现它们看上去实在令人讨厌,C风格的类型转换还可以继续使用并且合法。然而,正是因为新的类型转换符缺乏美感才能使它弥补了在含义精确性和可辨认性上的缺点。并且,使用新类型转换符的程序更容易被解析(不论是对人工还是对于工具程序),它们允许编译器检测出原来不能发现的错误。这些都是放弃C风格类型转换方法的强有力的理由。还有第三个理由:也许让类型转换符不美观和键入麻烦是一件好事。 

posted @ 2015-04-30 00:10  五字的梦想  阅读(341)  评论(0编辑  收藏  举报