再论类型转换
- 标准数据类型之间会进行隐式的类型安全转换
实例分析: 有趣的隐式类型转换
#include <iostream>
using 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 = -2000
i = -2000
ui = 1000
ui + i = 4294966296
Positive
sizeof(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 字节整型数计算最高效
问题
普通类型与类类型之间能否进行类型转换?
类类型之间能否进行类型转换?
编程实验: 普通类型 -> 类类型
#include <iostream>
using 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&)
结论:
编译器不支持普通类型到类类型的直接转换
转换构造函数
- 构造函数可以定义不同类型的参数
参数满足下列条件时称为转换构造函数
- 有且仅有一个参数
- 参数是基本类型
- 参数是其它类类型
编程实验: 普通类型 -> 类类型
#include <iostream>
using 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 = 5
t.value() = 5
~Test(), mValue = 5
编译器的行为
- 编译器会尽力尝试让源码通过编译
"5" 这个立即数默认为 int 类型,怎么可以赋值给 t 对象呢! 现在就报错吗?不急,我看看有没有转换构造函数! OK, 发现 Test 类中定义了 Test(int i),可以进行转换,默认等价于: t = Test(5) ,生成临时对象初始化 t ;
t = 5; <--> t = Test(5);
- 编译器尽力尝试的结果是隐式类型转换
隐式类型转化
- 会让程序以意想不到的方式进行工作
- 是工程中 bug 的重要来源
编程实验: 隐式转换的弊端
#include <iostream>
using 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 尝试
#include <iostream>
using 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<Test>(5);
//t = Test(5);
//t = (Test)5;
cout << "t.value() = " << t.value() << endl;
return 0;
}
输出:
Test()
Test(int i), i = 5
~Test(), mValue = 5
t.value() = 5
~Test(), mValue = 5
分析:
都会生成临时对象初始化 t
小结
- 转换构造函数只有一个参数
- 转换构造函数的参数类型是其它类型
- 转换构造函数在类型转换时被调用
- 隐式类型转换是工程中 bug 的重要来源
- explicit 关键字用于杜绝隐式类型转换
以上内容参考狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。