注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。
测试环境:Ubuntu 10.10
GCC版本:9.2.0
一、再论类型转换
1)标准数据类型之间会进行隐式的类型安全转换
2)转换规则如下:
实验分析
有趣的隐式类型转换
41-1.cpp
#include <iostream>
#include <string>
using namespace std;
int main()
{
short s = 'a';
unsigned int ui = 1000; //1000默认为int型
int i = -2000;
double d = i; //i是小类型,初始化大类型,安全
cout << "d = " << d << endl; //d = -2000
cout << "ui = " << ui << endl; //ui = 1000
cout << "ui + i = " << ui + i << endl; //
if( (ui + i) > 0 ) //i从int类型转化为unsigned int,然后ui + i,两个无符号整型相加>0
{
cout << "Positive" << endl; //正数
}
else
{
cout << "Negative" << endl; //负数
}
cout << "sizeof(s + 'b') = " << sizeof(s + 'b') << endl; //sizeof(s + b) = 4
//s从short转化为int,'b'从char转化为int,然后为了高效相加
return 0;
}
操作:
1) g++ 41-1.cpp -o 41-1.out编译正常,运行结果:
d = -2000
ui = 1000
ui + i = 4294966296
Positive
sizeof(s + 'b') = 4
二、问题
普通类型与类类型之间能否进行类型转换?类类型之间能否进行类型转换?
编程实验
普通类型->类类型
41-2.cpp
#include <iostream>
#include <string>
using namespace std;
class Test
{
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;
t = 5; //t = Test(5); 编译器进行隐式类型转换
Test r;
r = t + 10; //r = t + Test(10)==>调用Test operator + (const Test& p)函数
cout << r.value() << endl; //15
return 0;
}
操作:
1) g++ 41-2.cpp -o 41-2.out编译正确,打印结果:
15
分析:
编译器将数值进行隐式转换成类类型,然后进行赋值或者调用重载加法操作符函数。
2) 用explicit禁止隐式转换,代码如下:
#include <iostream>
#include <string>
using namespace std;
class Test
{
int mValue;
public:
Test()
{
mValue = 0;
}
explicit 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;
t = 5; //t = Test(5); 编译器进行隐式类型转换
Test r;
r = t + 10; //r = t + Test(10)==>调用Test operator + (const Test& p)函数
cout << r.value() << endl; //15
return 0;
}
g++ 41-2.cpp -o 41-2.out编译报错:
提示重载赋值操作符不能匹配、t=5不能正确赋值等等。
41-2.cpp:37:4: error: no match for ‘operator=’ (operand types are ‘Test’ and ‘int’)
t = 5;
错误:没有匹配的'operaotr='(操作数类型是'Test'和'int')
41-2.cpp:41:8: error: no match for ‘operator+’ (operand types are ‘Test’ and ‘int’)
r = t + 10;
错误:没有匹配的'operaotr='(操作数类型是'Test'和'int')
分析:
证明编译器进行了优化,普通类型被隐式转换成类类型。
3) 取消explicit,修改代码:
#include <iostream>
#include <string>
using namespace std;
class Test
{
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;
t = static_cast<Test>(5); // t = Test(5); Test(5)用临时对象初始化,隐式类型转换。这种转换是C++写法
Test r;
r = t + static_cast<Test>(10); // r = t + Test(10);
cout << r.value() << endl;
return 0;
}
g++ 41-2.cpp -o 41-2.out编译错误,打印结果:
15
分析:
无论是否用explicit修饰构造函数,都打印15。说明普通类型可以转换成类类型。
三、再讨论构造函数
1)构造函数可以定义不同类型的参数
2)参数满足下列条件时成为转换构造函数
- 有且仅有一个参数
- 参数是基本类型
- 参数是其它类类型
四、另一个视角
1)旧式的C方式强制类型转换
int i;
Test t;
i = int(1.5); //老旧转换方式,1.5转化为int
t = Test(100); //100强制转换成Test,本质是调用Test构造函数
五、编译器的行为
1)编译器会尽力尝试让源码通过编译
2)编译器尽力尝试的结果是隐式类型转换
3)隐式类型转换
- 会让程序以意想不到的方式进行工作
- 是工程中bug的重要来源
4)工程中通过了explicit关键字杜绝编译器的转换尝试
5)转换构造函数被explicit修饰时只能进行显示转换
- 转换方式(3种)
static_cast<ClassName>(value); //C++推荐方式
ClassName(value); //C方式,在C++里是手动调用构造函数
(ClassName)value; //C方式,不推荐
小结
1)转换构造函数只有一个参数
2)转换构造函数的参数类型是其它类型
3)转换构造函数在类型转换时被调用
4)隐式类型转换是工程中bug的重要来源
5)explicit关键字用于杜绝隐式类型转换