类型转换

【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.

顺序  选择  循环  坚持  总结

作者:kaizen
声明:本文版权归作者和博客园共有,欢迎转载。但未经作者同意必须保留此声明,且在文章明显位置给出本文链接,否则保留追究法律责任的权利。
签名:顺序 选择 循环
原文地址:https://www.cnblogs.com/Braveliu/p/2856046.html