再论类型转换
- 标准数据类型之间会进行隐式的类型安全转换
实例分析: 有趣的隐式类型转换
#includeusing namespace std;int main(){ short s = 'a'; unsigned int ui = 1000; int i = -2000; double d = i; cout << "d = " << d << endl; cout << "i = " << i << endl; cout << "ui = " << ui << endl; cout << "ui + i = " << ui + i << endl; // 注意这里! if( (ui + i) > 0 ) // 注意这里! { cout << "Positive" << endl; } else { cout << "Negative" << endl; } cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl; // 注意这里! return 0;}
输出:d = -2000i = -2000ui = 1000ui + i = 4294966296Positivesizeof(s + 'b') = 4
分析 1:
cout << "ui + i = " << ui + i << endl;
if( (ui + i) > 0 ) {}
ui 类型为 unsigned int; i 类型为 int;操作数类型不一致,i 将发生隐式类型转换到 unsigned int ,内存中的二进制数将被重新解读。计算结果为 unsigned int 类型。
分析 2:
sizeof(s + 'b');
s 类型为 short 'b' 类型为 char操作数类型不一致,s 将发生隐式类型转换到 int, 'b' 将发生隐式类型转换到 int。计算结果为 int 类型。
问: 为什么不是 'b'(char) 隐式转换为 s (short) 类型呢?
答: 4 字节整型数计算最高效问题
普通类型与类类型之间能否进行类型转换?
类类型之间能否进行类型转换?编程实验: 普通类型 -> 类类型
#includeusing namespace std;class Test{};int main(){ Test t; t = 5; return 0; }
输出:test.cpp: In function ‘int main()’:test.cpp:13: error: no match for ‘operator=’ in ‘t = 5’test.cpp:6: note: candidates are: Test& Test::operator=(const Test&)结论:编译器不支持普通类型到类类型的直接转换
转换构造函数
- 构造函数可以定义不同类型的参数
参数满足下列条件时称为转换构造函数
- 有且仅有一个参数
- 参数是基本类型
- 参数是其它类类型
编程实验: 普通类型 -> 类类型
#includeusing namespace std;class Test{private: int mValue;public: Test() { cout << "Test()" << endl; mValue = 0; } Test(int i) { cout << "Test(int i), i = " << i << endl; mValue = i; } int value() { return mValue; } ~Test() { cout << "~Test(), mValue = " << mValue << endl; }};int main(){ Test t; t = 5; // 注意这里! cout << "t.value() = " << t.value() << endl; return 0; }
输出:Test()Test(int i), i = 5~Test(), mValue = 5t.value() = 5~Test(), mValue = 5
编译器的行为
- 编译器会尽力尝试让源码通过编译
"5" 这个立即数默认为 int 类型,怎么可以赋值给 t 对象呢! 现在就报错吗?不急,我看看有没有转换构造函数! OK, 发现 Test 类中定义了 Test(int i),可以进行转换,默认等价于: t = Test(5) ,生成临时对象初始化 t ;
t = 5; <--> t = Test(5);
- 编译器尽力尝试的结果是隐式类型转换
隐式类型转化
- 会让程序以意想不到的方式进行工作
- 是工程中 bug 的重要来源
编程实验: 隐式转换的弊端
#includeusing namespace std;class Test{private: int mValue;public: Test() { mValue = 0; } Test(int i) { mValue = i; } Test operator + (const Test& p) { Test ret(mValue + p.mValue); return ret; } int value() { return mValue; }};int main(){ Test t(5); t = t + 10; // 注意这里! cout << "t.value() = " << t.value() << endl; return 0; }
输出:t.value() = 15
应用层分析:
类中重载了 + 操作符Test operator + (const Test& p)
, 可是右操作数参数类型为一个对象,为什么使用 整型值常量 可以进行相加操作呢? 是不是笔误? 编译器为什么没有报错呢? 实质分析:
t = t + 10;
<--> t = t + Test(10);
编译器进行了隐式类型转换。 结论:
t = t + 10;
t = 5;
尽量不使用这样的写法。可能笔误带来的书写,而编译器认为这种行为合法而导致问题。
- 工程中通过 explicit 关键字杜绝编译器的尝试转换
转换构造函数被 explicit 修饰时只能进行显示转换
转换方式
static_cast<ClassName>(value);
ClassName(value);
(ClassName)value; // 不推荐
编程实验: explicit 尝试
#includeusing namespace std;class Test{private: int mValue;public: Test() { cout << "Test()" << endl; mValue = 0; } explicit Test(int i) { cout << "Test(int i), i = " << i << endl; mValue = i; } Test operator + (const Test& p) { Test ret(mValue + p.mValue); return ret; } int value() { return mValue; } ~Test() { cout << "~Test(), mValue = " << mValue << endl; }};int main(){ Test t; t = static_cast (5); //t = Test(5); //t = (Test)5; cout << "t.value() = " << t.value() << endl; return 0; }
输出:Test()Test(int i), i = 5~Test(), mValue = 5t.value() = 5~Test(), mValue = 5分析:都会生成临时对象初始化 t
小结
- 转换构造函数只有一个参数
- 转换构造函数的参数类型是其它类型
- 转换构造函数在类型转换时被调用
- 隐式类型转换是工程中 bug 的重要来源
- explicit 关键字用于杜绝隐式类型转换
以上内容参考狄泰软件学院系列课程,请大家保护原创!