类型转换
【1】类型转换
诸位周知,类型分为内置数据类型和自定义数据类型(即就是类)。那么,类型转换也就从这两种情况进行讨论。
首先,有一个概念的认识:类型转换分为隐式类型转换与显式类型转换。
所谓隐身类型转换就是由编译器自己执行转换过程,无需程序员介入。
显式类型转换也称为强制类型转换,一般使用名字命名的强制类型转换操作符。
【2】隐身类型转换
(1)在混合类型的表达式中,其操作数被转换为相同的类型:
1 int iVal; 2 double dVal; 3 iVal >= dVal; //iVal 转换为 double
(2)用作条件的表达式被转换为bool类型:
1 int iVal; 2 if(iVal) //iVal转换为bool 3 while(cin) //cin转换为bool
(3)用一表达式初始化某个变量,或将一表达式赋值给某个变量,测该表达式被转换为该变量的类型:
1 int iVal = 3.14; //3.14转换为int 2 int *p = 0; //0 转换为空指针类型为int *
(4)算术转换(有符号与无符号类型之间的转换)
(5)指针转换
1 int ia[10]; 2 int *ip = ia; //ia转换为第一个元素的指针
(6)算术类型与bool类型转换
1 bool bVal = true; 2 int iVal = b; //iVal == 1 3 double pi = 3.14; 4 bool b2 = pi; //b2 为真 5 pi = false; //pi == 0
(7)转换为枚举类型
1 enum eVal {a, b, c, d}; 2 int iVal = b; //iVal == 1
(8)转换为const对象
1 int i; 2 const int ci = 0; 3 const int &j = i; //非常量转换为常整型引用 4 const int *p = &ci; //转换非常量地址为常量地址
(9)由标准类型定义的转换
1 string s; 2 while(cin>>s) //将istream类型转换为bool类型
(10)类中隐身转换
1 class A 2 { 3 int a; 4 public: 5 A(int x = 0 ):a(x) 6 { 7 8 } 9 }; 10 void main() 11 { 12 A obj = 100; //将整型转换为自定义类型A 13 }
【3】显式类型转换
显式类型转换操作符:static_cast, const_cast, dynamic_cast, reinterpret_cast。
(1)static_cast
命名上理解是静态类型转换。如double转换为char。
1 double dVal = 97.0; 2 char ch = static_cast<char>(dVal);
类似于C风格的强制转换。无条件转换,静态类型转换。用于:
<1>基类和子类之间转换:其中子类指针转换成父类指针是安全的;但是父类指针转换为子类指针是不安全的。(基类与子类之间的动态转换建议使用dynamic_cast)。
<2>基本数据类型转换。enum, struct, int, char, float等。static_const不能进行无关类型(如非基类和子类)指针之间的转换。
<3>把空指针转换为目标类型的空指针。
<4>把任何类型的表达式转换为void类型。
<5>static_cast不能去掉类型的const,volitale属性(用const_cast)。
(2)const_cast
去掉类型的const或volatile属性。
1 struct SA 2 { 3 int i; 4 }; 5 6 void main() 7 { 8 const SA ra; 9 //ra.i = 10; //直接修改const类型,编译错误 10 SA &rb = const_cast<SA&>(ra); 11 rb.i = 10; 12 }
(3)dynamic_cast
有条件转换,动态类型转换,运行时类型安全检查(转换失败返回NULL):
<1>安全的基类和子类之间转换。
<2>必须要有虚函数。
<3>相同基类不同子类之间的交叉转换。但结果是NULL。
1 #include<iostream> 2 using namespace std ; 3 4 class BaseClass 5 { 6 public: 7 int m_iNum; 8 virtual void foo(){}; 9 //基类必须有虚函数。保持多台特性才能使用dynamic_cast 10 }; 11 12 class DerivedClass: public BaseClass 13 { 14 public: 15 char *m_szName[100]; 16 void bar(){}; 17 }; 18 19 void main() 20 { 21 DerivedClass* pb = new DerivedClass(); 22 //子类->父类,静态类型转换,正确但不推荐 23 BaseClass *pd1 = static_cast<DerivedClass *>(pb); 24 //子类->父类,动态类型转换,正确 25 BaseClass *pd2 = dynamic_cast<DerivedClass *>(pb); 26 27 28 BaseClass* pb2 = new BaseClass(); 29 //父类->子类,静态类型转换,危险!访问子类m_szName成员越界 30 DerivedClass *pd21 = static_cast<DerivedClass *>(pb2); 31 //父类->子类,动态类型转换,安全的。结果是NULL 32 DerivedClass *pd22 = dynamic_cast<DerivedClass *>(pb2); 33 34 if(NULL == pd22) 35 { 36 cout<<"pd22 == NULL"<<endl; 37 } 38 } 39 40 /* 41 pd22 == NULL 42 */
(4)reinterpret_cast
仅仅重新解释类型,但没有进行二进制的转换:
<1>转换的类型必须是一个指针、引用、算术类型、函数指针或者成员指针。
<2>在比特位级别上进行转换。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换为一个整数,再把该整数转换为原类型的指针,还可以得到原先的指针值)。但不能将32bit的实例转成指针。
<3>最普通的用途就是在函数指针类型之间进行转换。
<4>很难保证移植性。
1 #include<iostream> 2 using namespace std ; 3 4 int doSomething() 5 { 6 return 0; 7 } 8 //FuncPtr 是一个指向函数的指针,该函数没有参数,返回值类型为 void 9 typedef void (*FuncPtr) (); 10 void main() 11 { 12 //10个FuncPtrs指针的数组 让我们假设你希望(因为某些莫名其妙的原因)把一个指向下面函数的指针存入funcPtrArray数组: 13 FuncPtr funcPtrArray[10]; 14 // 编译错误!类型不匹配,reinterpret_cast可以让编译器以你的方法去看待它们:funcPtrArray 15 // funcPtrArray[0] = &doSomething; 16 //不同函数指针类型之间进行转换 17 funcPtrArray[0] = reinterpret_cast<FuncPtr>(&doSomething); 18 }
总结:
1:去const属性使用const_cast。
2:基本类型转换使用static_cast。
3:多态类之间的类型转换使用dynamic_cast。
4:不同类型之间的指针类型转换使用reinterpret_cast。
Good Good Study, Day Day Up.
顺序 选择 循环 坚持 总结