C++继承了C中的隐式和显式转换的方式。但这种转换并不是安全和严格的,
加上C++本身对象模型的复杂性,C++增加了四个显示转换的关键字。(C++是强类型语言)
经过编码测试,小结如下:
const_cast:仅用于去掉完全同类型的const,volatile约束,不能含有任何其它类型的转换,若不含约束也可以相当于没转换
static_cast:使用类型可在继承的方向上向上或向下转换,不进行安全检查。
子类转父类,值、引用、指针形式均可,其中指针还可以是常量
父类转子类,值不可以,引用和指针均可,子类中的多余成员值是乱码
不支持不同无关类之间的转换
dynamic_cast:动态转换,使用类型可在继承的方向上向上或向下转换,进行安全检查。
子类转父类,值不可以,引用、指针均可,其中指针还可以是常量
父类转子类,值不可以,引用可通过编译,但运行失败。指针可通过编译,该转换也能运行,但是后面再调用方法时会检查类型,判断是否失败。
不同无关类之间的转换均不能运行,但多态类可通过编译
reinterpret_cast:强制类型转换,不改变原有数据,只是重新解释内存
子类转父类,值不可以,引用、指针形式均可,其中指针还可以是常量
父类转子类,值不可以,引用和指针均可,子类中的多余成员值是乱码
不同无关类之间的转换,值不可以,引用和指针均可,重新解释内存
注意对能成功进行的含virtual方法的类,通过引用转换和指针转换后对virtual方法的调用不同:
假设转换前为pref_class转换后为post_class,则通过引用转化调virtual方法实际是调用post_class中对应方法的;通过指针转换调post_class中virtual指针相对存放位置对应pref_class相对位置的指针对应的方法(若该位置指向不是方法,运行失败),形参不一致会自动补全(一般是乱码)或删减
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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(){b=3;other=5;} 28 virtual void display_v() { printf("Otherclass virtual method %d %d\n",b,other);} 29 int other; 30 int b; 31 }; 32 int main() 33 { 34 Base *bbp,bb(4); 35 Derived *ddp,dd(7,6); 36 Base *newb=new Base(2); 37 Derived *newd=new Derived(3,1); 38 Otherclass ot,*otp=new Otherclass; 39 ////test1:static_cast 40 41 // bb=static_cast<Base> (dd); 42 // bb.display();// Base 7 43 // bb.display_v();//Base virtual method 7 44 // bb=static_cast<Base&> (dd); 45 // bb.display();// Base 7 46 // bb.display_v();//Base virtual method 7 47 // newb=static_cast<Base*> (newd); 48 // newb->display();// Base 3 49 // newb->display_v();//Derived virtual method 3 1 50 // dd=static_cast<Derived> (bb);//error 无构造函数可以接受源类型,或构造函数重载决策不明确 51 // dd=static_cast<Derived&> (bb);//right 52 // dd.display();// Derived 4 6625256 53 // dd.display_v();//Derived virtual method 4 6625256 54 // newd=static_cast<Derived*> (newb);//right 55 // newd->display();//Derived 2 838805478 56 // newd->display_v();//Base virtual method 2 57 58 // bb=static_cast<Base> (ot);//error 无法从“Otherclass”转换为“Base” 无构造函数可以接受源类型,或构造函数重载决策不明确 59 // bb=static_cast<Base&> (ot);//error 无法从“Otherclass”转换为“Base &” 引用的 static_cast 和 safe_cast 只能用于有效初始化或用于相关类之间的左值转换 60 // bbp=static_cast<Base*> (otp);//error无法从“Otherclass *”转换为“Base *” 与指向的类型无关;转换要求 reinterpret_cast、C 样式转换或函数样式转换 61 62 ////test2:static_cast 63 // bb=dynamic_cast<Base> (dd);//error 目标类型必须是指向已定义类的指针或引用 64 // bb=dynamic_cast<Base&> (dd); 65 // bb.display();// Base 7 66 // bb.display_v();//Base virtual method 7 67 // newb=dynamic_cast<Base*> (newd); 68 // newb->display();// Base 3 69 // newb->display_v();//Derived virtual method 3 1 70 // dd=dynamic_cast<Derived> (bb);//error 目标类型必须是指向已定义类的指针或引用 71 // dd=dynamic_cast<Derived&> (bb);//error 编译通过,运行失败//即使bb已成为Derived对象的引用,运行也失败 72 // newd=dynamic_cast<Derived*> (newb);//编译通过,// 73 // newd->display();//运行失败,//若newb实际指向Derived对象则成功运行 74 // bb=dynamic_cast<Base> (ot);//error 目标类型必须是指向已定义类的指针或引用 75 // bb=dynamic_cast<Base&> (ot);//若Otherclasss是多态类型,含virtual方法则编译通过运行失败;若“Otherclass”不是多态类型,编译失败 76 // bbp=dynamic_cast<Base*> (otp);//若Otherclasss是多态类型,含virtual方法则编译通过,下面方法调用运行失败;若“Otherclass”不是多态类型,编译失败 77 // bbp->display(); 78 // bbp->display_v(); 79 80 81 82 ////test3:reinterpret_cast 83 // bb=reinterpret_cast<Base> (dd);//error 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用 84 // bb=reinterpret_cast<Base&> (dd); 85 // bb.display();// Base 7 86 // bb.display_v();//Base virtual method 7 87 // newb=reinterpret_cast<Base*> (newd); 88 // newb->display();// Base 3 89 // newb->display_v();//Derived virtual method 3 1 90 // dd=reinterpret_cast<Derived> (bb);// error 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用 91 // dd=reinterpret_cast<Derived&> (bb);//right 92 // dd.display();// Derived 4 6625256 93 // dd.display_v();//Derived virtual method 4 6625256 94 // newd=reinterpret_cast<Derived*> (newb);//right 95 // newd->display();//Derived 2 838805478 96 // newd->display_v();//Base virtual method 2 97 98 // bb=reinterpret_cast<Base> (ot);//error 无法从“Otherclass”转换为“Base” 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用 99 // bb=reinterpret_cast<Base&> (ot);//right 100 // bb.display();//Base 5 101 // bb.display_v();//Base virtual method 5 102 // bbp=reinterpret_cast<Base*> (otp);//right 103 // bbp->display();//Base 5 104 // bbp->display_v();//Otherclass virtual method 3 5 105 106 107 ////test4:const_cast 108 const Base cbb(4); 109 Base *const cbbp=new Base(2); 110 const Derived cdd(7,6); 111 Derived *const cddp=new Derived(3,1); 112 // bb=const_cast<Base> (cbb);//error 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用 113 // bb=const_cast<Base&> (*cbbp);//right 114 // bb=const_cast<Base&> (cbb);//right 115 // bb=const_cast<Base&> (cdd);//error 无法从“const Derived *”转换为“Base *”,类型的差异不在于限定符;不能单独使用 const_cast 116 // bb=static_cast<Base&> (cbb); //error 无法从“const Base”转换为“Base &” 引用的 static_cast 和 safe_cast 只能用于有效初始化或用于相关类之间的左值转换 117 // bb=dynamic_cast<Base&> (cbb); //不能使用“dynamic_cast”从“const Base”转换到“Base &” 118 // bb=reinterpret_cast<Base&> (cbb); //error 无法从“const Base *”转换为“Base *” 转换丢失限定符 119 120 // 121 // bbp=const_cast<Base*> (cbbp);//right 122 // bbp=const_cast<Base*> (cddp);//无法从“Derived *const ”转换为“Base *” 类型的差异不在于限定符;不能单独使用 const_cast 123 // bbp=static_cast<Base*> (cbbp);//right 124 // bbp->set(2); 125 // bbp->display();//Base 2 126 // bbp=dynamic_cast<Base*> (cbbp);// right 127 // bbp->set(2); 128 // bbp->display();//Base 2 129 // bbp=reinterpret_cast<Base*> (cbbp);// right 130 // bbp->set(2); 131 // bbp->display();//Base 2 132 133 volatile Base vbb(4); 134 Base *volatile vbbp=new Base(2); 135 volatile Derived vdd(7,6); 136 Derived *volatile vddp=new Derived(3,1); 137 // bb=const_cast<Base> (vbb);//error 无法从“volatile Base”转换为“Base” 转换要求构造函数或用户定义的转换运算符,而该运算符不能由 const_cast 或 reinterpret_cast 使用 138 // bb=const_cast<Base&> (vbb);//right 139 // bb=const_cast<Base&> (vdd);//error 无法从“volatile Derived *”转换为“Base *” 类型的差异不在于限定符;不能单独使用 const_castt 140 // 141 // bbp=const_cast<Base*> (vbbp);//right 142 // bbp=const_cast<Base*> (vddp);//无法从“Derived *volatile ”转换为“Base *” 类型的差异不在于限定符;不能单独使用 const_cast 143 144 int a=3; 145 const double cd=3.0; 146 //a=const_cast<int> (cd);//无法从“const double”转换为“int” 转换是有效的标准转换,可以隐式执行或通过使用 static_cast、C 样式转换或函数样式转换执行 147 return 0; 148 }
附:摘自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。