C++中四种强制类型转换

来源:互联网 发布:冰川远征网络剑仙 编辑:程序博客网 时间:2024/06/13 21:19

 将一种类型转换为另一种类型,转换后的变量,它的内部数据存储方式也随之发生改变,c++有四个显示的类型转换函数,reinterpret_cast,const_cast,static_cast,dynamic_cast.前面三个是在编译期间实现转换的,最后一个是在运行时实现转换,还可返回转换成功与否标志。

 

转换函数的原型如下:

reinterpret_cast<new_type>(expression)

const_cast<new_type>(expression)

static_cast<new_type>(expression)

dynamic_cast<new_type>(expression)

将expression表达式的值转换为new_type类型的值。

 

static_cast

用于基本类型和具有继承关系的类型之间的转换。会改变变量的内部表示方式。继承类和基类的指针可以相互转换,继承类可转换为基类,不可转化基本类型的指针,基类不可转换为继承类。下面分别谈谈static_cast的几种常见用法。

 

①用于类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。进行上行转换(把派生类的指针或引用转换成基类表示)是安全的;进行下行转换(把基类指针或引用转换成派生类表示)时,由于没有动态类型检查,所以是不安全的。

例如:

[cpp] view plaincopy
  1. class A{};  
  2.   
  3. class B:public A  
  4. {};  
  5.   
  6. /*类层次结构中基类(父类)和派生类(子类)之间指针或引用的转换。*/  
  7.  A * pointer_a;  
  8.  B b;  
  9.  pointer_a=static_cast<A *>(&b);  

 

②用于基本数据类型之间的转换,如把int转换成char,把int转换成enum。这种转换的安全性也要开发人员来保证。

例如:

[cpp] view plaincopy
  1. /*基本类型之间的强制转化*/  
  2. int i;  
  3. float f=1.2f;  
  4. i=static_cast<int>(f);  

 

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

例如:

[cpp] view plaincopy
  1. /*把空指针转换成目标类型的空指针*/  
  2. void * vp;  
  3. char * cp=static_cast<char *>(vp);  
 

 

reinterpret_cast

将一个类型的指针转换为另一个类型的指针,不修改指针变量值数据存放格式,只在编译时重新解释指针的类型。不能用于非指针类型的转换。还可将一个指针值转换为整型数。即expression必须是个指针类型。不能将const指针转换为void*指针。

例如:

 

[cpp] view plaincopy
  1. /*reinterpret_cast主要是将数据从一种指针类型的转换为另一种指针类型。*/  
  2. char * cp;  
  3. int * ip;  
  4. ip=reinterpret_cast<int *>(cp);  

 

const_cast:

去除指针变量的常量属性,将它转换为一个对应指针类型的普通变量。也可将一个非常量的指针变量转换为一个常指针变量。不能将非指针的常量变为普通变量。下面分别谈谈const_cast的几种常见用法。

 

①常量指针被转化成非常量指针,并且仍然指向原来的对象;

例如:

[cpp] view plaincopy
  1. const char * const_cp;  
  2. char * nonconst_cp=const_cast<char *>(const_cp);  

 

②常量引用被转换成非常量引用,并且仍然指向原来的对象;

例如:

[cpp] view plaincopy
  1. const int const_var=10;  
  2. int &var=const_cast<int&>(const_var);  

 

③常量对象被转换成非常量对象。

例如:

[cpp] view plaincopy
  1. class A  
  2. {  
  3. public:  
  4.     int a;  
  5.     A(int value):a(value){}//构造函数  
  6. };  
  7.   
  8. int main()  
  9. {  
  10.     const A const_a(10);  
  11.     A & nonconst_a=const_cast<A &>(const_a);  
  12.         nonconst_a.a=20;  
  13.         cout<<"The value of const_a.a is: "<<const_a.a<<endl;  
  14.         return 0;  
  15. }  

 

注意:任何尝试通过const_cast去修改一个const常量值的操纵都是徒劳的。

例如:

 

[cpp] view plaincopy
  1. int a=34;  
  2. const int * pcint=&a;  
  3. int * pint=const_cast<int*>(pcint);  
  4. *pint=0;  

      这样就修改了a的值(a==0),这里如果改为const int a=34;那么虽然编译依然能通过,运行依然OK,但是实际上当你用*pint来修改a的值时,a的值依然为34,而*pint确实为0了,更为有趣的是此时pint=&a依然成立,虽然pint指向a,但是取出它的值却不等于a了。

 

dynamic_cast

只能在继承类对象的指针之间或引用之间进行转换。

vc++编译器默认禁止使用RTTI信息,若要使用dynamic_cast,需执行“工程-设置”在“c++”选项卡中,选择“c++language”,勾选“允许运行时类型信息RTTI”。

 

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

      该运算符把expression转换成type-id类型的对象。type-id必须是类的指针、类的引用或者void *; 如果type-id是类指针类型,那么expression也必须是一个指针,如果type-id是一个引用,那么expression也必须是一个引用。dynamic_cast主要用于类层次间的上行转换和下行转换,还可以用于类之间的交叉转换。 在类层次间进行上行转换时,dynamic_cast和static_cast的效果是一样的; 在进行下行转换时,dynamic_cast具有类型检查的功能,比static_cast更安全。

例如:

 

 

[c-sharp] view plaincopy
  1. class B  
  2. {   
  3. public:   
  4.   int m_iNum;   
  5.   virtual void foo();   
  6. };   
  7.   
  8. class D:public B  
  9. {   
  10. public:   
  11.     char *m_szName[100];   
  12. };   
  13.   
  14.   
  15. void func(B *pb)  
  16. {  
  17.    D *pd1 = static_cast<D *>(pb);   
  18.    D *pd2 = dynamic_cast<D *>(pb);   
  19. }  
 

 

    在上面的代码段中,如果pb指向一个D类型的对象,pd1和pd2是一样的,并且对这两个指针执行D类型的任何操作都是安全的;但是,如果pb指向的是一个B类型的对象,那么pd1将是一个指向该对象的指针,对它进行D类型的操作将是不安全的(如访问m_szName),而pd2将是一个空指针。另外要注意:B要有虚函数,否则会编译出错;static_cast则没有这个限制。B中需要检测有虚函数的原因:类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。这是由于运行时类型检查需要运行时类型信息,而这个信息存储在类的虚函数表(关于虚函数表的概念,详细可见<Inside c++ object model>)中,只有定义了虚函数的类才有虚函数表,没有定义虚函数的类是没有虚函数表的。另外,dynamic_cast还支持交叉转换(cross cast)。如下代码所示。

  

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

 

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

0 0
原创粉丝点击