C++ 类型转换(Casting Operators)

   在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必须用于有继承关系的类之间,如果两个类指针之间没有任何关系,则会报编译错误。

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

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

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

    //dynamic_cast_1.cpp
    // compilewith: /c
    class B {};
    class C :public B { };
    class D :public C { };

    void f(D*pd) {
     C* pc =dynamic_cast<C*>(pd);  // ok: C is a direct base class
                                  // pc points to C subobject of pd
      B* pb =dynamic_cast<B*>(pd);  // ok: B is an indirect base class
                                  // pb points to B subobject of pd
    }

    voidfunc(B *pb){
       D *pd1 =static_cast<D *>(pb);
       D *pd2 =dynamic_cast<D *>(pb);
    }

 

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

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

   dynamic_cast还支持交叉转换:

    classA
    {
   public:
    intm_iNum;
    virtual voidf(){}
    };

    classB:public A{};
    classD:public A{};
 
    voidfoo()
    {
       B *pb = newB;
      pb->m_iNum = 100;
       D *pd1 =static_cast<D *>(pb); //copileerror
       D *pd2 =dynamic_cast<D *>(pb); //pd2 isNULL
       deletepb;
    }

 

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


3、const_cast

   

    语法形式:

   const_cast <type-id> ( expression)

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

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

    举个例子:

    classB
    {
      public:
       intm_iNum;
    }
    voidfoo()
    {
       const Bb1;
       b1.m_iNum =100; //comile error
       B b2 =const_cast<B>(b1);
       b2. m_iNum =200; //fine
    }

 

   上面的代码编译时会报错,因为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指针。

 

   //expre_reinterpret_cast_Operator.cpp
    // compilewith: /EHsc
    #include<iostream>

    // Returns ahash code based on an address
    unsignedshort Hash( void *p ) {
      unsigned intval = reinterpret_cast<unsigned int>(p );
      return (unsigned short )( val ^ (val >>16));
    }

    usingnamespace std;
    int main(){
      inta[20];
      for ( int i= 0; i < 20; i++ )
         cout<< Hash( a + i )<< endl;
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值