C++显示类型转换

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 = 30
COME BACK To me !! Value of X = 10 Value of Y = 30
Value of X = 10 Value of Y = 30
After the first cast .. Value of X = 10 Value of Y = 30
After settings the value to 0 .. Value of X = 0 Value of Y = 30
COME BACK To me !! Value of X = 0 Value of Y = 30
The 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   
}  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值