C++ 类型转换(Casting Operators)

转自:http://blog.csdn.net/leehong2005/article/details/8602030

在C++中,经常会涉及到类型转换,虽说一般情况下不建议类型转换,但有时候还是避免不了。转换的时候,可能一般都直接使用C语言风格的转换(直接强制转换),但这样做可能很不安全,容易造成数据丢失(如int -> char),内存访问违规。

    下面讲一讲C++的几个转换操作符,常见的有这么几个:static_cast, dynamic_cast, const_cast, reinterpret_cast。这里所讲的几乎都是参考MSDN,地址如下:

    ms-help://MS.MSDNQTR.v90.chs/dv_vclang/html/16240348-26bc-4f77-8eab-57253f00ce52.htm


1、static_cast

   

    语法形式:

    static_cast <type-id> ( expression )

    该操作符把expression转换成type-id的类型,这里面没有类型检查,所以它的安全性不能得到保证。

    1,static_cast可以用于转换基类指针到派生类指针,进行上行转换(把子类的指针或引用转换成基类指针)是安全,进行下行转换(基类指针或引用转成子类指针)是不安全的。

    2,用于基本数据类型之间的转换,如把int转成char,int转成enum,这种转换的安全性只能由开发人员来保证,因为int转char可能会导致数据丢失,从而造成逻辑错误。

    3,static_cast可以转换空指针到目标类型的空指针。

    4,static_cast可以把任何类型转换成void类型,目标类型可以包含const,volatile,或__unaligned属性。

    5,static_cast不能转换掉const,volatile,或__unaligned属性。

    6,如果要用来转换类指针,如果类A与类B之间没有任何关系,那么会报编译错误。


2、dynamic_cast

   

    语法形式:

    dynamic_cast <type-id> ( expression )

    把expression转换成type-id类型,type-id必须是一个类的指针、类的引用或者void*,如果type-id是一个指针,那么expression必须是一个指针,如果type-id是引用,那么expression必须是一个引用。

    dynamic_cast主要用于类层次之间的上行转换和下行转换,还可以用于类之间的交叉转换(Cross)。

    dynamic_cast必须用于有继承关系的类之间,如果两个类指针之间没有任何关系,则会报编译错误。

    在Visual C++ 2005中,当type-id不是所转类型的指针的话,dynamic_cast不会再抛异常,它会返回0。

    在类层次之间进行上行转换时,dynamic_cast和static_cast的效果是一样的,但在进行下行转换时,dynamic_cast具有类型检查功能,比static_cast更安全。(如果基类指针根本就不是指向子类,dynamic_cast返回NULL,而static_cast照样能转换成功,此时是不安全的)。

    我们一起来看一下下面这段代码:

    

[cpp]  view plain copy
  1. // dynamic_cast_1.cpp  
  2. // compile with: /c  
  3. class B { };  
  4. class C : public B { };  
  5. class D : public C { };  
  6.   
  7. void f(D* pd) {  
  8.   C* pc = dynamic_cast<C*>(pd);   // ok: C is a direct base class  
  9.                                // pc points to C subobject of pd  
  10.    B* pb = dynamic_cast<B*>(pd);   // ok: B is an indirect base class  
  11.                                // pb points to B subobject of pd  
  12. }  
  13. void func(B *pb){  
  14.     D *pd1 = static_cast<D *>(pb);  
  15.     D *pd2 = dynamic_cast<D *>(pb);  
  16. }  

 

    在上面的代码中,如果pb指向一个D类型的对象,pd1和pd2是一样的,并且对这两个指针执行D类型的任何操作都是安全的,但是,如果pb指向的是一个B类型的对象,那么static_cast也能转换成功,那么用pd1(D类型)去访问D类型的一些方法时,可能就会出异常,而对于dynicma_cast,它就会返回一个NULL,表示转换不成功,注意了,这个函数是有性能开销的,因为它要进行类型检查等操作。

    另外,对于dynamic_cast,B类型需要有虚函数,否则编译要出错(这种情况必须是下行转换,即从上向下转换),因为dynamic_cast会进行运行时类型检查,而这个信息存储在类的虚函数表中,只有定义了虚函数的类才会有虚函数表,没有定义虚数的类是没有虚函数表的,所以编译就会出错,而对于static_cast则没有限制,因为它不进行运行时类型检查。

    dynamic_cast还支持交叉转换:

    

[cpp]  view plain copy
  1. class A  
  2. {  
  3. public:  
  4. int m_iNum;  
  5. virtual void f(){}  
  6. };  
  7.   
  8. class B:public A{};  
  9. class D:public A{};  
  10.   
  11. void foo()  
  12. {  
  13.     B *pb = new B;  
  14.     pb->m_iNum = 100;  
  15.     D *pd1 = static_cast<D *>(pb); //copile error  
  16.     D *pd2 = dynamic_cast<D *>(pb); //pd2 is NULL  
  17.     delete pb;  
  18. }  

 

    在函数foo中,使用static_cast进行转换是不被允许的,将在编译时出错;而使用 dynamic_cast的转换则是允许的,结果是空指针。


3、const_cast

   

    语法形式:

    const_cast <type-id> ( expression )

    该运算符用来修改类型的constg或volatile属性。除了const或volatile修饰之外,type-id和expression的类型是一样的。

    这个用得最多的就是常量指针转换成非常量指针,常量引用转换成非常量引用,并且仍是指向原来对象或仍是原来对象的引用。

    举个例子:

[cpp]  view plain copy
  1. class B  
  2. {  
  3.     public:  
  4.     int m_iNum;  
  5. }  
  6. void foo()  
  7. {  
  8.     const B b1;  
  9.     b1.m_iNum = 100; //comile error  
  10.     B b2 = const_cast<B>(b1);  
  11.     b2. m_iNum = 200; //fine  
  12. }  

 

    上面的代码编译时会报错,因为b1是一个常量对象,不能对它进行改变;使用const_cast把它转换成一个常量对象,就可以对它的数据成员任意改变。注意:b1和b2是两个不同的对象。


4、reinterpret_cast

   

    语法形式:

    reinterpret_cast <type-id> ( expression )

    type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以将char* 转成 int*,类A的指针转成类B的指针,这样的转换是不安全的。reinperpre_cast不能去掉const, volatile或__unaligned属性。它可以将一个NULL指针转换成目标类型的NULL指针。

[cpp]  view plain copy
  1. // expre_reinterpret_cast_Operator.cpp  
  2. // compile with: /EHsc  
  3. #include <iostream>  
  4.   
  5. // Returns a hash code based on an address  
  6. unsigned short Hash( void *p ) {  
  7.    unsigned int val = reinterpret_cast<unsigned int>( p );  
  8.    return ( unsigned short )( val ^ (val >> 16));  
  9. }  
  10.   
  11. using namespace std;  
  12. int main() {  
  13.    int a[20];  
  14.    for ( int i = 0; i < 20; i++ )  
  15.       cout << Hash( a + i ) << endl;  
  16. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值