1. 再论类型转换(隐式转化和强制类型转换)
(1)标准数据类型之间会进行隐式的类型安全转换
(2)转换规则:
8个字节 long: 8个字节 long long: 8个字节 unsigned long: 8个字节
小类型(占用内存小)--->大类型(占用内存大)-----隐式转化(安全,不会发生程序的截断和数据的丢失)
实验:编程避免不同类型转换,编译器进行的隐式转换很可怕
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; //unsigned_-->int 10 int i = -2000; 11 double d = i; //小类型初始化大类型是安全的 12 13 cout << d << endl; //-2000 14 cout << ui<< endl; //1000 15 cout << ui+i << endl; //验证:ui+i =4294966296 16 17 //因为i会被转为unsigned int类型,两个无符号整形数相加,变成一个很大的正数。 18 //编程避免隐式类型转换 19 20 if ((ui + i) > 0) //编译器进行隐式类型转换,将i(小类型)转换为unsigned int(大类型) 21 { 22 cout << "positive" << endl; //negative 23 } 24 else 25 { 26 cout << "negative" << endl; 27 } 28 29 //根据标准数据类型的转换规则s->int。'b'为char,也会被转为int型。所以输出4 30 31 cout << "sizeof(s+'b')=" << sizeof(s + 'b') << endl; //4 32 //编译期将s和b都转换为Int 33 return 0; 34 }
问题:
实验:普通到类类型
1 #include<iostream> 2 #include<string> 3 4 using namespace std; 5 6 //类之间可不可以进行类型转换 7 class Test 8 { 9 int mvalue; 10 public: 11 Test() 12 { 13 } 14 15 Test(int i) //转换构造函数 16 { 17 mvalue = i; 18 } 19 Test operator + (const Test& p) 20 { 21 Test ret(mvalue + p.mvalue); 22 23 return ret; 24 } 25 26 int value() 27 { 28 return mvalue; 29 } 30 31 }; 32 int main() 33 { 34 Test t; 35 36 // t = (Test)5; //类型怎么转换???? 37 // t = Test(5); //直接调用构造函数,会产生一个临时对象,临时对象赋值给t对象,他俩属于Test对象 38 //编译器进行隐式类型转换-----本质调用转换构造函数 39 40 t = 5; //没有转化构造函数之前,错误 41 //有转换构造函数定义,等价于t=Test(5); 正确 42 43 Test r; 44 r = t + 10; //相当于:r = t + Test(10); 手误10整形,将2个Test对象相加,调用构造函数----error 45 46 cout << r.value() << endl; //15 47 48 return 0; 49 }
2. 普通类型到类类型的转换——转换构造函数
也可以将其他类类型转换到当前类类型
(1)构造函数可以定义不同类型的参数
(2)参数满足下列条件时称为转换构造函数
①有且仅有一个参数
②参数是基本类型
③参数是其它类类型(但不是本类的const引用,因为那叫拷贝构造函数)
(3)另一个视角:旧式的C方式强制类型转换
int i = int(1.5); //将浮点转为整型,有点像函数调用 Test t;
t = Test(100); //老旧的C转换方式,100整形强制类型转换到类类型,本质---调用构造函数 有点像函数调用
但是这样子隐式转化是不好的,实验说明:和上面一样
Test r;
r = t + 10; //相当于:r = t + Test(10); 手误10整形,将2个Test对象相加,调用构造函数----error
cout << r.value() << endl; //15
怎么解决?????
3. explicit关键字-----
(1)编译器隐式转换行为:
①编译器会尽力尝试让源码通过编译
Test t;
t = 100; //100这个立即数,默认为int型,怎么可能赋值给t对象呢?现在就报错
//吗?不急,编译器会看看有没有转换构造函数!Ok,发现Test类中定义
//Test(int i),可以进行转换,默认等价于:t = Test(100);
②隐式类型转换会让程序以意想不到的方式进行工作,是工程中Bug的重要来源。
(2)杜绝编译器的隐式类型转换:explicit关键字
①用explicit修饰转换构造函数。这时会阻止编译器隐式地尝试调用这个函数的行为。
②当转换构造函数被explicit修饰时,只能手动进行显式的转换,转换方式:
-
-
A.static_cast<ClassName>(value); //C++
-
B.ClassName(value); //C--手动调用构造函数
-
C.(ClassName)value; //不推荐
-
转换构造函数之前加了explicit----编译器不会自动调用转换构造函数,需要手动调用
1 #include <iostream>
2
3 using namespace std;
4
5 class Test
6 {
7 int mValue;
8
9 public:
10
11 Test() { mValue = 0; }
12
13 explicit Test(int i) //转换构造函数
14 {
15 mValue = i;
16 }
17
18 Test operator + (const Test& p)
19 {
20 Test ret(mValue + p.mValue);
21
22 return ret;
23 }
24
25 int value()
26 {
27 return mValue;
28 }
29
30 };
31
32
33
34 int main()
35 {
36 Test t;
37
38 //t = 5; //error,将5赋值给t对象,编译器会尝试调用Test(int i)转换构造函数
39
40 //但由于Test(int i)前面用explicit修饰,以后拒绝了这种尝试。所以
41
42 //编译不通过。
43
44
45 t = static_cast<Test>(5); //相当于 t = Test(5); 原因:Test(int i)被explicit修饰,
46
47 //就是告诉编译器要阻止那种通过隐式调用该函数的行为发生。
48
49 //只有显式调用Test(int i)(或通过强制类型方式转换的)
50
51 //才允许调用这个函数来进行类型的转换。
52
53
54 Test r;
55
56 //r = t + 10; error
t=(Test)5; //c语言方式,不推荐
57
58 r = t + static_cast<Test>(10); //c++推荐写法
59
60 cout << r.value() << endl; //15;
61
62 return 0;
63 }
4. 小结
(1)转换构造函数只有一个参数 explicit Test(int i)
(2)转换构造函数的参数类型是其它类型
(3)转换构造函数在类型转换时被调用
(4)隐式类型转换是工程中Bug的重要来源
(5)explicit关键字用于杜绝编译器这种隐式类型转换的行为