const_cast,static_cast,dynamic_cast,reinterpret_cast的区别

Posted ttii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了const_cast,static_cast,dynamic_cast,reinterpret_cast的区别相关的知识,希望对你有一定的参考价值。

C++继承了C中的隐式和显式转换的方式。但这种转换并不是安全和严格的,

加上C++本身对象模型的复杂性,C++增加了四个显示转换的关键字。(C++是强类型语言)

经过编码测试,小结如下:

const_cast:仅用于去掉完全同类型的const,volatile约束,不能含有任何其它类型的转换,若不含约束也可以相当于没转换
static_cast:使用类型可在继承的方向上向上或向下转换,不进行安全检查。
      子类转父类,值、引用、指针形式均可,其中指针还可以是常量
      父类转子类,值不可以,引用和指针均可,子类中的多余成员值是乱码
      不支持不同无关类之间的转换
dynamic_cast:动态转换,使用类型可在继承的方向上向上或向下转换,进行安全检查。
      子类转父类,值不可以,引用、指针均可,其中指针还可以是常量
      父类转子类,值不可以,引用可通过编译,但运行失败。指针可通过编译,该转换也能运行,但是后面再调用方法时会检查类型,判断是否失败。
      不支持不同无关类之间的转换
reinterpret_cast:强制类型转换
      子类转父类,值不可以,引用、指针形式均可,其中指针还可以是常量
      父类转子类,值不可以,引用和指针均可,子类中的多余成员值是乱码
      不同无关类之间的转换,值不可以,引用和指针均可,方法正常调用但多余成员值是乱码

技术分享
  1 // test  static_cast dynamic_cast
  2 #include <stdio.h>
  3 #include <stdlib.h>
  4 using namespace std;
  5 class Base
  6 {
  7     public:
  8     Base () {b=0;}
  9     Base(int i){b=i;}
 10     int b;
 11     void display(){ printf("Base %d \n",b);}
 12     virtual void display_v() { printf("Base virtual method %d \n",b);}
 13     void set(int i) {b=i;}
 14 };
 15 class Derived: public Base
 16 {
 17     public:
 18     Derived () {b=0;d=-1;}
 19     Derived(int i,int j):Base(i){d=j;}
 20     int d;
 21     void display() { printf("Derived %d %d \n",b,d);}
 22     void display_v() { printf("Derived virtual method %d %d \n",b,d);}
 23 };
 24 class Otherclass
 25 {
 26     public:
 27     Otherclass(){}
 28     int other;
 29 };
 30 int main()
 31 {
 32     Base *bbp,bb(4);
 33     Derived *ddp,dd(7,6);
 34     Base *newb=new Base(2);
 35     Derived *newd=new Derived(3,1);
 36     Otherclass ot,*otp;
 37 ////test1:static_cast
 38     
 39 //    bb=static_cast<Base> (dd);
 40 //    bb.display();// Base 7
 41 //    bb.display_v();//Base virtual method 7
 42 //    bb=static_cast<Base&> (dd);
 43 //    bb.display();// Base 7
 44 //    bb.display_v();//Base virtual method 7
 45 //    newb=static_cast<Base*> (newd);
 46 //    newb->display();// Base 3
 47 //    newb->display_v();//Derived virtual method 3 1
 48 //    dd=static_cast<Derived> (bb);//error 无构造函数可以接受源类型,或构造函数重载决策不明确
 49 //    dd=static_cast<Derived&> (bb);//right
 50 //    dd.display();// Derived 4 6625256 
 51 //    dd.display_v();//Derived virtual method 4 6625256 
 52 //    newd=static_cast<Derived*> (newb);//right
 53 //    newd->display();//Derived 2 838805478
 54 //    newd->display_v();//Base virtual method 2
 55 
 56 //       bb=static_cast<Base> (ot);//error 无法从“Otherclass”转换为“Base” 无构造函数可以接受源类型,或构造函数重载决策不明确
 57 //       bb=static_cast<Base&> (ot);//error 无法从“Otherclass”转换为“Base &” 引用的 static_cast 和 safe_cast 只能用于有效初始化或用于相关类之间的左值转换
 58 //      bbp=static_cast<Base*> (otp);//error无法从“Otherclass *”转换为“Base *” 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换
 59 
 60 ////test2:static_cast
 61 //  bb=dynamic_cast<Base> (dd);//error 目标类型必须是指向已定义类的指针或引用
 62 //    bb=dynamic_cast<Base&> (dd);
 63 //    bb.display();// Base 7
 64 //    bb.display_v();//Base virtual method 7
 65 //    newb=dynamic_cast<Base*> (newd);
 66 //    newb->display();// Base 3
 67 //    newb->display_v();//Derived virtual method 3 1
 68 //    dd=dynamic_cast<Derived> (bb);//error 目标类型必须是指向已定义类的指针或引用
 69 //    dd=dynamic_cast<Derived&> (bb);//error 编译通过,运行失败//即使bb已成为Derived对象的引用,运行也失败
 70 //    newd=dynamic_cast<Derived*> (newb);//编译通过,//
 71 //    newd->display();//运行失败,//若newb实际指向Derived对象则成功运行
 72 //       bb=dynamic_cast<Base> (ot);//error  目标类型必须是指向已定义类的指针或引用
 73 //       bb=dynamic_cast<Base&> (ot);//error “Otherclass”不是多态类型
 74 //      bbp=dynamic_cast<Base*> (otp);//error “Otherclass”不是多态类型
 75 
 76 
 77 ////test3:reinterpret_cast
 78 //    bb=reinterpret_cast<Base> (dd);//error 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用
 79 //    bb=reinterpret_cast<Base&> (dd);
 80 //    bb.display();// Base 7
 81 //    bb.display_v();//Base virtual method 7
 82 //    newb=reinterpret_cast<Base*> (newd);
 83 //    newb->display();// Base 3
 84 //    newb->display_v();//Derived virtual method 3 1
 85 //    dd=reinterpret_cast<Derived> (bb);// error 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用
 86 //    dd=reinterpret_cast<Derived&> (bb);//right
 87 //    dd.display();// Derived 4 6625256 
 88 //    dd.display_v();//Derived virtual method 4 6625256 
 89 //    newd=reinterpret_cast<Derived*> (newb);//right
 90 //    newd->display();//Derived 2 838805478
 91 //    newd->display_v();//Base virtual method 2
 92 
 93 //       bb=reinterpret_cast<Base> (ot);//error 无法从“Otherclass”转换为“Base” 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用
 94 //       bb=reinterpret_cast<Base&> (ot);//right
 95 //        bb.display();//Base 20257015 
 96 //      bbp=reinterpret_cast<Base*> (otp);//right
 97 //      bbp->display();//Base 418153452 
 98 
 99 ////test4:const_cast
100     const Base cbb(4);
101     Base *const cbbp=new Base(2);
102     const Derived cdd(7,6);
103     Derived *const cddp=new Derived(3,1);
104 //  bb=const_cast<Base> (cbb);//error 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用
105 //  bb=const_cast<Base&> (*cbbp);//right
106 //  bb=const_cast<Base&> (cbb);//right
107 //  bb=const_cast<Base&> (cdd);//error 无法从“const Derived *”转换为“Base *”,类型的差异不在于限定符;不能单独使用 const_cast
108 //  bb=static_cast<Base&> (cbb);  //error 无法从“const Base”转换为“Base &” 引用的 static_cast 和 safe_cast 只能用于有效初始化或用于相关类之间的左值转换
109 //  bb=dynamic_cast<Base&> (cbb);  //不能使用“dynamic_cast”从“const Base”转换到“Base &”
110 //  bb=reinterpret_cast<Base&> (cbb);  //error  无法从“const Base *”转换为“Base *” 转换丢失限定符
111 
112 // 
113 //  bbp=const_cast<Base*> (cbbp);//right
114 //  bbp=const_cast<Base*> (cddp);//无法从“Derived *const ”转换为“Base *” 类型的差异不在于限定符;不能单独使用 const_cast
115 //  bbp=static_cast<Base*> (cbbp);//right
116 //  bbp->set(2);
117 //  bbp->display();//Base 2 
118 //  bbp=dynamic_cast<Base*> (cbbp);// right
119 //  bbp->set(2);
120 //  bbp->display();//Base 2 
121 //  bbp=reinterpret_cast<Base*> (cbbp);// right
122 //  bbp->set(2);
123 //  bbp->display();//Base 2 
124  
125     volatile Base vbb(4);
126     Base *volatile vbbp=new Base(2);
127     volatile Derived vdd(7,6);
128     Derived *volatile vddp=new Derived(3,1);
129 //  bb=const_cast<Base> (vbb);//error 无法从“volatile Base”转换为“Base”  转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用
130 //  bb=const_cast<Base&> (vbb);//right
131 //  bb=const_cast<Base&> (vdd);//error 无法从“volatile Derived *”转换为“Base *”  类型的差异不在于限定符;不能单独使用 const_castt
132 // 
133 //  bbp=const_cast<Base*> (vbbp);//right
134 //  bbp=const_cast<Base*> (vddp);//无法从“Derived *volatile ”转换为“Base *” 类型的差异不在于限定符;不能单独使用 const_cast
135 
136     int a=3;
137     const double cd=3.0;
138     //a=const_cast<int> (cd);//无法从“const double”转换为“int”  转换是有效的标准转换,可以隐式执行或通过使用 static_cast、C 样式转换或函数样式转换执行
139     return 0;
140 }
View Code

 

附:摘自http://blog.csdn.net/starryheavens/article/details/4617637

1.1       reinpreter_cast

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

type-id必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。

这个操作符能够在非相关的类型之间转换。操作结果只是简单的从一个指针到别的指针的值的二进制拷贝。在类型之间指向的内容不做任何类型的检查和转换。reinpreter_cast是特意用于底层的强制转型,导致实现依赖(就是说,不可移植)的结果。

int n=9;

// reinterpret_cast 仅仅是复制 n 的比特位到 d,因此d 包含无用值。

double d=reinterpret_cast<double & > (n);

1.2       const_cast

用法:const_cast<type_id> (expression)

用于修改类型的const或volatile属性。除了const 或volatile修饰之外,type_id和expression的类型是一样的,一般用于强制消除对象的常量性。它是唯一能做到这一点的 C++ 风格的强制转型,而C不提供消除const的机制(已验证)。

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

1.3       static_cast

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

该运算符把expression转换为type-id类型,但没有运行时类型检查来保证转换的安全性。它允许执行任意的隐式转换和相反转换动作。主要有如下几种用法:

1)用于基本数据类型之间的转换,如把int转换成char,non-const 对象转型为 const 对象(这里相反方向不可以,C++只有const_cast可以)。

2)把空指针转换成目标类型的指针。(之前的做法是用强制转换(type-id*))

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

4)应用到类的指针上,它允许子类类型的指针转换为父类类型的指针(upercasting这是一个有效的隐式转换);也能够执行相反动作,即转换父类为它的子类(downcasting),这种转换的安全性需要开发人员来保证(主要是在非上下转型中)。

class Base {};

class Derived : public Base {};

Base *a = new Base;

Derived *b = NULL;

b = static_cast<Derived *>(a); //可以通过编译,但存在安全隐患(如访问//Derived的成员)

注意:

1.static_cast不能转换掉expression的const、volitale、或者__unaligned属性。

2.在非基本类型或上下转型中,被转换的父类需要检查是否与目的类型相一致,否则,如果在两个完全不相干的类之间进行转换,将会导致编译出错。

1.4       dynamic_cast

只用于对象的指针和引用,主要用于执行“安全的向下转型”,也就是说,要确定一个对象是否是一个继承体系中的一个特定类型。它是唯一不能用旧风格语法执行的强制转型,也是唯一可能有重大运行时代价的强制转型。

当用于多态类型时(包含虚函数),它允许任意的隐式类型转换以及相反过程。不过,与static_cast不同,在后一种情况里(即隐式转换的相反过程),dynamic_cast根据RTTI信息检查操作是否有效。即在转换时dynamic_cast会检查转换是否能返回一个被请求的有效的完整对象。这种检查不是语法上的,而是真实情况的检查。检测在运行时进行,如果被转换的指针不是一个被请求的有效完整的对象指针,返回值为NULL。


 

以上是关于const_cast,static_cast,dynamic_cast,reinterpret_cast的区别的主要内容,如果未能解决你的问题,请参考以下文章

static_cast, dynamic_cast, const_cast讨论

什么时候应该使用 static_cast、dynamic_cast、const_cast 和 reinterpret_cast?

什么时候应该使用 static_cast、dynamic_cast、const_cast 和 reinterpret_cast?

const_cast,static_cast,dynamic_cast,reinterpret_cast的区别(转)

static_castdynamic_castreinterpret_cast和const_cast

关于C++中的类型转换