目录
2. 强制类型转换( static_cast、const_cast、reinterpret_cast、dynamic_cast)
类型转换可分为 隐式类型转换(编译器自动完成) 与 强制类型转换(需要自己操作)。
隐式类型转换
基本数据类型之间会进行隐式的类型安全转换。其转换规则如下:
我们用 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++中,还有其它几种隐式类型转换(后续讲解),那么现在试想一下这几个问题:
-
基本类型 可以转换为 类类型吗?--- 可以,见转换构造函数;
-
类类型 可以转换为 基本类型吗?--- 可以,见类型转换函数;
-
类类型之间可以转换吗?--- 可以,见转换构造函数 和 类型转换函数;
注:这种隐式类型转换不能够抑制,并且也是bug的来源之一;
强制类型转换
在介绍c++强制类型转换前,我们可以回顾一下c语言中的强制类型转换。c语言中的强制类型转换十分简单、粗暴,即 (Type)(Expression);或者 Type(Expression);但是,这种简单的强制类型转换引发了很多问题,可归纳为如下2点:
-
任意类型之间都可以进行转换,编译器很难判断其正确性(过于粗暴);
-
在源码中无法快速定位所有使用强制类型转换的语句(很难定位);
所以,基于这2点考虑,在c++中引入了新式类型转换( static_cast、const_cast、reinterpret_cast、dynamic_cast),其使用方法可归纳为 xxx_cast
1、static_cast
-
用于 基本类型间的转换
-
不能用于基本类型指针间的转换
-
用于有继承关系类对象之间的转换和类指针之间的转换
-
用于 其它类型(基本类型和类类型) 向 类类型之间的转换;static_cast<类类型>(其它类型),见转换构造函数。
2、 const_cast
-
用于去除变量的只读属性
-
强制转换的目标类型必须是指针或引用
3、 reinterpret_cast
-
用于指针类型间的强制转换
-
用于整数和指针类型间的强制转换
4、 dynamic_cast
-
用于有继承关系的类指针(引用)间的转换
-
用于有交叉关系的类指针(引用)间的转换
-
相关类(基类)中必须有虚函数的支持
-
具有类型检查的功能,但类型转换的结果只可能在运行阶段得到;
指针转换:
转换成功:得到目标类型的指针;
转换失败:得到一个空指针;
引用转换:
转换成功:得到目标类型的引用;
转换失败:得到一个异常操作的信息;
dynamic_cast 转换时错误提示:
- 不能将父类指针 直接 转换为 子类指针
- 在 父类中没有虚函数,不能发生多态 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 = %dn", k); // 5
27 printf("j = %dn", j); // 5
28
29 y = 8;
30
31 printf("x = %dn", x); // 2
32 printf("y = %dn", y); // 8
33 printf("&x = %pn", &x);// 0x7fffd40b84e8
34 printf("&y = %pn", &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 }
static_cast、const_cast、reinterpret_cast、dynamic_cast 初体验
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 测试案列
通过 《 static_cast 与 dynamic_cast 测试案列 》可知,当使用 dynamic_cast 强制类型转换时,即 Derived dp = dynamic_cast
当使用 static_cast 强制类型转换时,即 Derived dp = static_cast
从运行结果可知, static_cast 与 dynamic_cast 在继承中进行类指针转换时是存在差异的;其中,
- 相同点:当父类指针 指向 子类对象时,二者都可以将父类指针 成功转换为 子类指针;
- 不同点:当父类指针 指向 父类对象时,
1) static_cast 转换:可以将父类指针 成功转换为 子类指针;
2)dynamic_cast 转换:父类指针 不能够转换为 子类指针;
对于 static_cast 与 dynamic_cast 的使用情况还可以查阅另一篇博客 《 c++中的类型识别 》中的 如何实现动态类型 这一节。
类型转换函数
1、转换构造函数
当构造函数只有1个参数 且参数的类型是基本类型 或者是 其它类型时,就是转换构造函数。其作用是将其他类型 转换为 类类型;
编译器尽力尝试的结果是隐式类型转换,隐式类型转换是工程中bug的重要来源;
工程中通过explicit关键字杜绝隐式转换,转换构造函数被explicit修饰时只能进行显示转换;
转换方式
-
static_ cast
(value); -
ClassName(value);
-
(ClassName)value; //不推荐
在类型转换时调用转换构造函数。
1 #include <iostream>
2 #include <string>
3
4 using namespace std;
5
6 class Test
7 {
8 int mValue;
9 public:
10 Test()
11 {
12 mValue = 0;
13 }
14
15 explicit Test(int i)
16 {
17 mValue = i;
18 }
19
20 Test operator + (const Test& p)
21 {
22 Test ret(mValue + p.mValue);
23
24 return ret;
25 }
26
27 int value()
28 {
29 return mValue;
30 }
31 };
32
33 int main()
34 {
35 Test t;
36 Test r;
37
38 // 隐式类型转换 不加explicit关键字
39 //t = 5; // t = Test(5);
40 //r = t + 10; // r = t + Test(10);
41
42 t = static_cast<Test>(5); // t = Test(5);
43 r = t + static_cast<Test>(10); // r = t + Test(10);
44
45 cout << r.value() << endl; // 15
46
47 return 0;
48 }
转换构造函数之 基本类型 -> 类类型
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 转换构造函数
结论:
-
类型转换函数 与 转换构造函数 具有同等的地位;
-
无法抑制隐式的类型转换函数调用,此时 类型转换函数可能与转换构造函数冲突(类类型之间的转换);
-
在类型转换时 调用类型转换函数 、转换构造函数。
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 */
类类型之间的相互转换
// 类型转换函数与转换构造函数发生冲突 的示意图
原文链接: https://www.cnblogs.com/nbk-zyc/p/12383810.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/193787
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!