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++中,还有其它几种隐式类型转换(后续讲解),那么现在试想一下这几个问题:
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. 用于 基本类型间的转换
2. 不能用于基本类型指针间的转换
3. 用于有继承关系类对象之间的转换和类指针之间的转换
4. 用于 其它类型(基本类型和类类型) 向 类类型之间的转换;static_cast<类类型>(其它类型),见转换构造函数。
1. 用于去除变量的只读属性
2. 强制转换的目标类型必须是指针或引用
1. 用于指针类型间的强制转换
2. 用于整数和指针类型间的强制转换
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); // 转换成功,可以将父类指针对象转换为子类指针对象 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 转换:父类指针 不能够转换为 子类指针;
当构造函数只有1个参数 且 参数的类型是基本类型 或者是 其它类型时,就是转换构造函数。其作用是将其他类型 转换为 类类型;
编译器尽力尝试的结果是隐式类型转换,隐式类型转换是工程中bug的重要来源;
工程中通过explicit关键字杜绝隐式转换,转换构造函数被explicit修饰时只能进行显示转换;
转换方式
1. static_ cast<ClassName >(value);
2. ClassName(value);
3. (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 }
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 }
结论:
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 */
// 类型转换函数与转换构造函数发生冲突 的示意图
原文:https://www.cnblogs.com/nbk-zyc/p/12383810.html