C++显示类型转换

来源:互联网 发布:夏佐淘宝店铺地址 编辑:程序博客网 时间:2024/04/30 15:30

C++显示类型转换

http://blog.csdn.net/dlmu2001/article/details/6004613 

阅读webkit代码,遭遇C++显示转换,复习下。

过去几年,我更多的是在同C语言打交道,在C语言中,强制类型转换非常简单。

double pi=3.14;

int piInt=(int)pi;

这个强制类型转换会丢失部分数据(.14),所以如果不加(int)做强制转换,严检查的编译会报错,宽检查的编译会报warning。

在C语言中,指针是4字节或者8字节的,所以指针之间的强制转换在转换的时候就如同不同的int之间的赋值,问题不大,问题在于对该指针的使用上,必须确保该指针确实可以做出这样的强制转换。常见的情况是void*到不同的指针类型(比如内存分配,参数传递),char*和unsigned char*这样的转换。也有在读文件的时候,直接把某个结构映射为内存,写文件的时候,把某块内存直接映射成结构体。

标准C++提供了更好的转换方法,一种无论对程序员和代码解析器都有利的方式。

标准C++中主要有4种显示类型转换类型运算符:reinterpret_cast,static_cast,const_cast,dynamic_cast。

1.reinterpret_cast

语法:

returnvalue=reinterpret_cast(casting value);

这个操作符修改了操作数类型,但仅仅是重新解释了对象的比特模型而没有进行二进制转换。

从语法上看,这个操作符仅用于指针类型的转换(返回值是指针)。它用来将一个类型指针转换为另一个类型指针,它只需在编译时重新解释指针的类型。

这个操作符基本不考虑转换类型之间是否是相关的。

reinterpret_cast的本质(http://blog.csdn.net/coding_hello/archive/2008/03/24/2211466.aspx)一文做的试验很好的解释了reinterpret_cast不做二进制转换的特点。我喜欢从C语言的角度来理解这个操作符,就像C语言中的指针强制转换,其实只是把地址赋给了新的指针,其它的不做改变,只在新的指针使用的时候,进行不一样的解释。看如下的例子:

#include  using namespace std; class classA{  public:    int valueX;    int valueY;     classA() { valueX = 0; valueY = 0;} }; int main(){  classA *a = new classA();  a->valueX = 10;  a->valueY = 30;  cout << "Value of X = " << a->valueX << " Value of Y = "  << a->valueY << endl;   void *aClassVoid = reinterpret_cast<void*>(a);   a = reinterpret_cast(aClassVoid);   cout << "COME BACK To me !! Value of X = " << a->valueX << " Value of Y = "  << a->valueY << endl;   cout << "Value of X = " << a->valueX << " Value of Y = "  << a->valueY << endl;  aClassVoid = reinterpret_cast<void*>(a);  // but if you alter the values within a variable once you have done the first cast.  cout << "After the first cast .. Value of X = " << a->valueX << " Value of Y = "  << a->valueY << endl;  a->valueX = 0;  cout << "After settings the value to 0 .. Value of X = " << a->valueX << " Value of Y = "  << a->valueY << endl;  //and try again with the casting with the aClassVoid  classA *AP = reinterpret_cast(aClassVoid);   cout << "COME BACK To me !! Value of X = " << AP->valueX << " Value of Y = "  << AP->valueY << endl;   cout << "The last reinterpret_cast leaves the value as 0 for valueX because it is still only pointing to the same place as 'a'" << endl;    return 0;}

输出结果:

Value of X = 10 Value of Y = 30COME BACK To me !! Value of X = 10 Value of Y = 30Value of X = 10 Value of Y = 30After the first cast .. Value of X = 10 Value of Y = 30After settings the value to 0 .. Value of X = 0 Value of Y = 30COME BACK To me !! Value of X = 0 Value of Y = 30The last reinterpret_cast leaves the value as 0 for valueX because it is still only pointing to the same place as 'a'

可以看出,这个转换只是指针地址的赋值。在reinterpret_cast的本质(http://blog.csdn.net/coding_hello/archive/2008/03/24/2211466.aspx)一文中,只有在cout的时候,参数被不同地进行的解释,才出现的不同的结果。

reinterpret_cast常用的场景如下:

1)普通指针转换,T*—>U*—>T*,保证T*经过一些列转换值不变

比如将不同类型的指针存在一个容器里,vector可以存int*,char*,string*等各种指针,只要有别的方式确定某个void*当初的类型是T*,标准保证reinterpret_cast(v[i])可以得到当初的值。

2)自己做memory allocator,可以将T*转换为U*,这个时候可能要注意字节对其的问题。

 

2.static_cast

语法:T static_cast (expression);

该运算符把expression转换成type-id类型,但没有运行时类型检查来保证转换的安全性。

static_cast是最经常用到的转换操作符,它最经常的一个应用就是将隐式转换变成显示转换,以消除编译器可能产生的warning,同reinterpret_cast不同,采用static_cast转换的两个类型之间一般有某种相关性。

static_cast主要应用场景如下:

1)用于类层次结构中基类和派生类之间指针或引用的转换。这个转换中,将派生类转成基类是安全的,将基类转成派生类时由于没有进行动态类型检查,所以是不安全的。

2)用于基本数据之间的转换。如把int转成char,int转成num等。

3)把空指针转换成目标类型的空指针。

4)把任何类型的表达式转换成void类型。

除了空指针之外,static_cast并不经常用来做指针转换,因为它的效率不高。

int in=99;   double dn=static_cast<double> (in);//用于转换基本类型和具有继承关系的类新之间转换     class Base{};   class derv:public Base{};   derv dd;   Base bbbb=static_cast(dd);//具有继承关系的类型之间转换            Base *pb1=new Base;   derv *pder=static_cast(pb1);//基类转继承类   derv* pder1=new derv;   Base* pbase1=static_cast(pder1);//继承类指针转父类指针

3.dynamic_cast

语法:dynamic_cast < type-id > ( expression )

该运算符把expression转换成type-id类型的对象。Type-id必须是类的指针、类的引用或者void *;

dynamic_cast的转换是在运行时进行的,它的一个好处是会在运行是做类型检查,如果对象的类型不是期望的类型,它会在指针转换的时候返回NULL,并在引用转换的时候抛出一个std::bad_cast异常。

dynamic_cast一般只在继承类对象的指针之间或引用之间进行类型转换。如果没有继承关系,则被转化的类具有虚函数对象的指针进行转换。

 struct A {    virtual void f() { }  };  struct B : public A { };  struct C { };   void f () {    A a;    B b;     A* ap = &b;    B* b1 = dynamic_cast (&a);  // NULL, because 'a' is not a 'B'    B* b2 = dynamic_cast (ap);  // 'b'    C* c = dynamic_cast (ap);   // NULL.     A& ar = dynamic_cast (*ap); // Ok.    B& br = dynamic_cast (*ap); // Ok.    C& cr = dynamic_cast (*ap); // std::bad_cast  }

4.const_cast
语法:

const_cast< type-id > (exdivssion)

这个运算符可以用来去除一个对象的const或volatile属性。type-id必须是一个指针或者引用。

class B{   public:   int m_iNum;   }   void foo(){   const B b1;   b1.m_iNum = 100; //comile error   B b2 = const_cast((b1);   b2. m_iNum = 200; //fine   }  
原创粉丝点击