目录
1. 隐式类型转换
2. 强制类型转换( static_cast、const_cast、reinterpret_cast、dynamic_cast)
3. 类型转换函数、转换构造函数
类型转换可分为 隐式类型转换(编译器自动完成) 与 强制类型转换(需要自己操作)。
隐式类型转换
基本数据类型之间会进行隐式的类型安全转换。其转换规则如下:
我们用 1个案列来介绍这种隐式类型转换规则,会有意想不到的结果发生....!!!
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 int main()
7 {
8 short s = 'a';
9 unsigned int ui = 1000;
10 int i = -2000;
11 double d = i;
12
13 cout << "d = " << d << endl;
14 cout << "ui = " << ui << endl;
15 cout << "ui + i = " << ui + i << endl;
16
17 if( (ui + i) > 0 ) // 变量i会进行隐式类型转换 -> unsigned int // ui + i > 0
18 {
19 cout << "Positive" << endl;
20 }
21 else
22 {
23 cout << "Negative" << endl;
24 }
25
26 cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl; // 4 // s -> int 'b' -> int // sizeof(s + 'b') = sizeof(int) // 编译器默认是int运算
27
28 return 0;
29 }
30 /*
31 d = -2000
32 ui = 1000
33 ui + i = 4294966296
34 Positive
35 sizeof(s + 'b') = 4
36 */
在c++中,还有其它几种隐式类型转换(后续讲解),那么现在试想一下这几个问题:
1. 基本类型 可以转换为 类类型吗?--- 可以,见转换构造函数;
2. 类类型 可以转换为 基本类型吗?--- 可以,见类型转换函数;
3. 类类型之间可以转换吗?--- 可以,见转换构造函数 和 类型转换函数;
注:这种隐式类型转换不能够抑制,并且也是bug的来源之一;
强制类型转换
在介绍c++强制类型转换前,我们可以回顾一下c语言中的强制类型转换。c语言中的强制类型转换十分简单、粗暴,即 (Type)(Expression);或者 Type(Expression);但是,这种简单的强制类型转换引发了很多问题,可归纳为如下2点:
1. 任意类型之间都可以进行转换,编译器很难判断其正确性(过于粗暴);
2. 在源码中无法快速定位所有使用强制类型转换的语句(很难定位);
所以,基于这2点考虑,在c++中引入了新式类型转换( static_cast、const_cast、reinterpret_cast、dynamic_cast),其使用方法可归纳为 xxx_cast<Type>(Expression) 。
1、static_cast
1. 用于 基本类型间的转换
2. 不能用于基本类型指针间的转换
3. 用于有继承关系类对象之间的转换和类指针之间的转换
4. 用于 其它类型(基本类型和类类型) 向 类类型之间的转换;static_cast<类类型>(其它类型),见转换构造函数。
2、 const_cast
1. 用于去除变量的只读属性
2. 强制转换的目标类型必须是指针或引用
3、 reinterpret_cast
1. 用于指针类型间的强制转换
2. 用于整数和指针类型间的强制转换
4、 dynamic_cast
1. 用于有继承关系的类指针(引用)间的转换
2. 用于有交叉关系的类指针(引用)间的转换
3. 相关类(基类)中必须有虚函数的支持
4. 具有类型检查的功能,但类型转换的结果只可能在运行阶段得到;
指针转换:
转换成功:得到目标类型的指针;
转换失败:得到一个空指针;
引用转换:
转换成功:得到目标类型的引用;
转换失败:得到一个异常操作的信息;
dynamic_cast 转换时错误提示:
1. 不能将父类指针 直接 转换为 子类指针
2. 在 父类中没有虚函数,不能发生多态 polymorphic
1 #include <stdio.h>
2
3 void static_cast_demo()
4 {
5 int i = 0x12345;
6 char c = 'c';
7 int* pi = &i;
8 char* pc = &c;
9
10 c = static_cast<char>(i);
11 pc = static_cast<char*>(pi); // error static_cast 不能用于基本类型指针之间 的转换
12 }
13
14 void const_cast_demo()
15 {
16 const int& j = 1;
17 int& k = const_cast<int&>(j);
18
19 const int x = 2;
20 int& y = const_cast<int&>(x);
21
22 int z = const_cast<int>(x); // error const_cast 强制转换的目标类型必须是指针或引用类型
23
24 k = 5;
25
26 printf("k = %d\n", k); // 5
27 printf("j = %d\n", j); // 5
28
29 y = 8;
30
31 printf("x = %d\n", x); // 2
32 printf("y = %d\n", y); // 8
33 printf("&x = %p\n", &x);// 0x7fffd40b84e8
34 printf("&y = %p\n", &y);// 0x7fffd40b84e8
35 }
36
37 void reinterpret_cast_demo()
38 {
39 int i = 0;
40 char c = 'c';
41 int* pi = &i;
42 char* pc = &c;
43
44 pc = reinterpret_cast<char*>(pi);
45 pi = reinterpret_cast<int*>(pc);
46 pi = reinterpret_cast<int*>(i);
47 c = reinterpret_cast<char>(i); // error reinterpret_cast 适用于指针类型之间的转换 和 整型与指针类型之间的转换
48 }
49
50 void dynamic_cast_demo()
51 {
52 int i = 0;
53 int* pi = &i;
54 char* pc = dynamic_cast<char*>(pi); // error
55 }
56
57 int main()
58 {
59 static_cast_demo();
60 const_cast_demo();
61 reinterpret_cast_demo();
62 dynamic_cast_demo();
63
64 return 0;
65 }
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 class Base
7 {
8 public:
9 Base()
10 {
11 cout << "Base::Base()" << endl;
12 }
13
14 virtual ~Base()
15 {
16 cout << "Base::~Base()" << endl;
17 }
18 };
19
20 class Derived : public Base
21 {
22 public:
23 Derived()
24 {
25 cout << "Derived::Derived()" << endl;
26 }
27
28 void func()
29 {
30 cout << "Derived::func()" << endl;
31 }
32
33 virtual ~Derived()
34 {
35 cout << "Derived::~Derived()" << endl;
36 }
37 };
38
39 void test1()
40 {
41 Base* bp = new Derived();
42
43 Derived *dp = dynamic_cast<Derived*>(bp); // 当父类指针指向的是子类对象,转换成功
44 //Derived *dp = static_cast<Derived*>(bp); // 当父类指针指向的是子类对象,转换成功
45 if( dp != NULL )
46 {
47 cout << "dp = " << dp << endl;
48 dp->func();
49 }
50 else
51 {
52 cout << "Cast error!" << endl;
53 }
54
55 delete bp;
56 }
57
58 void test2()
59 {
60 Base* bp = new Base();
61
62 Derived *dp = dynamic_cast<Derived*>(bp); // 转化失败,不能将父类指针对象转换为子类指针对象
63 //Derived *dp = static_cast<Derived*>(bp); // 转换成功,可以将父类指针对象转换为子类指针对象,但可能有 Bug 存在
64 if( dp != NULL )
65 {
66 cout << "dp = " << dp << endl;
67 dp->func();
68 }
69 else
70 {
71 cout << "Cast error!" << endl;
72 }
73
74 delete bp;
75 }
76
77 int main()
78 {
79 test1();
80
81 cout << "-----------------------" << endl;
82
83 test2();
84
85 return 0;
86 }
通过 《 static_cast 与 dynamic_cast 测试案列 》可知,当使用 dynamic_cast 强制类型转换时,即 Derived *dp = dynamic_cast<Derived*>(bp); 程序的运行结果为:
当使用 static_cast 强制类型转换时,即 Derived *dp = static_cast<Derived*>(bp); 程序的运行结果为:
从运行结果可知, static_cast 与 dynamic_cast 在继承中进行类指针转换时是存在差异的;其中,
1. 相同点:当父类指针 指向 子类对象时,二者都可以将父类指针 成功转换为 子类指针;
2. 不同点:当父类指针 指向 父类对象时,
1) static_cast 转换:可以将父类指针 成功转换为 子类指针;
2)dynamic_cast 转换:父类指针 不能够转换为 子类指针;
对于 static_cast 与 dynamic_cast 的使用情况还可以查阅另一篇博客 《 c++中的类型识别 》中的 如何实现动态类型 这一节。
类型转换函数
1、转换构造函数
当构造函数只有1个参数 且 参数的类型是基本类型 或者是 其它类型时,就是转换构造函数。其作用是将其他类型 转换为 类类型;
编译器尽力尝试的结果是隐式类型转换,隐式类型转换是工程中bug的重要来源;
工程中通过explicit关键字杜绝隐式转换,转换构造函数被explicit修饰时只能进行显示转换;
转换方式
1. static_ cast<ClassName >(value);
2. ClassName(value);
3. (ClassName)value; //不推荐
在类型转换时调用转换构造函数。
转换构造函数之 基本类型 -> 类类型
2、类型转换函数
c++ 中可以定义类型转换函数,其作用是将 类类型 转换为 其它类型;其语法格式为:
1 // 类型转换函数语法格式
2 operator Type()
3 {
4 Type ret;
5
6 // ...
7
8 retuan Type;
9 }
编译器能够隐式的使用类型转换函数
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 class Test
7 {
8 int mValue;
9 public:
10 Test(int i = 0)
11 {
12 mValue = i;
13 }
14 int value()
15 {
16 return mValue;
17 }
18 operator int ()
19 {
20 return mValue;
21 }
22 };
23
24 int main()
25 {
26 Test t(100);
27 int i = t; // 隐式的使用类型转换函数 operator int ()
28
29 cout << "t.value() = " << t.value() << endl; // t.value() = 100
30 cout << "i = " << i << endl; // i = 100
31
32 return 0;
33 }
3、类型转换函数 VS 转换构造函数
结论:
1. 类型转换函数 与 转换构造函数 具有同等的地位;
2. 无法抑制隐式的类型转换函数调用,此时 类型转换函数可能与转换构造函数冲突(类类型之间的转换);
3. 在类型转换时 调用类型转换函数 、转换构造函数。
4. 工程中以Type toType()的公有成员 代替 类型转换函数;
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 class Test;
7
8 class Value
9 {
10 public:
11 Value()
12 {
13 }
14 explicit Value(Test& t)
15 {
16 cout << "explicit Value(Test& t)" << endl;
17 }
18 };
19
20 class Test
21 {
22 int mValue;
23 public:
24 Test(int i = 0)
25 {
26 mValue = i;
27 }
28 int value()
29 {
30 return mValue;
31 }
32 operator Value()
33 {
34 Value ret;
35 cout << "operator Value()" << endl;
36 return ret;
37 }
38 };
39
40 int main()
41 {
42 Test t(100);
43 Value v1 = t; // 隐式的调用类型转换函数 operator Value()
44 Value v2 = static_cast<Value>(t); // 显示的调用转换构造函数 explicit Value(Test& t)
45
46 return 0;
47 }
48 /*
49 运行结果:
50 operator Value()
51 explicit Value(Test& t)
52 */
// 类型转换函数与转换构造函数发生冲突 的示意图