如果表达式包含不同内置类型的操作数,并且不存在显式强制转换,则编译器将使用内置的标准转换来转换其中一个操作数,使这些类型匹配。
编译器将尝试按一个明确定义的顺序进行转换,直到有一个转换成功。
- 如果所选转换是提升转换,则编译器不会发出警告
- 如果转换是是收缩转换,则编译器会发出有关数据可能丢失的警告。( 尽管是否真的发生数据丢失取决于涉及的实际值,但我们建议您将此警告视为错误。)
我们来看个例子:混用数值类型的转换
int a = 0;
long b = a + 1; // int 转换为 long
if (a == b) {
// 默认的operator==须要a的类型和b相同,所以也发生转换
}
int转成long是向上转换,一般不会有太大问题,而long到int则极可能致使数据丢失,所以要尽可能避免后者。
如果涉及到用户定义的类型,则编译器将尝试使用在类中指定的转换,如果编译器找不到可以接受的转换,则发出错误而且不会编译
有关用户定义的转换的详细信息,请参阅 (c + +/cli) 的用户定义的转换。
C++语言中定义其基础类型之间的转换。还定义指针、引用、指向成员的指针派生类型的转换。这些转换叫做标准转换
整型提升
整数类型的对象可以转换为另一个更宽的整型类型,也就是说可以转换为另一表示更大值集的类型。这种扩大类型中的转换叫整型提升
下面就是整形提升:
long long_num1, long_num2;
int int_num;
// int_num promoted to type long prior to assignment.
long_num1 = int_num;
// int_num promoted to type long prior to multiplication.
long_num2 = int_num * long_num2;
有符号类型与无符号类型相互转换
有符号转无符号
- 有符号整数类型的对象可以转为对应的无符号类型。
- 发生这种转换时,实际的位模式不会更改,但是数据的解释会发生改变:
#include <iostream>
using namespace std;
int main()
{
short i = -3;
unsigned short u;
cout << (u = i) << "\n";
}
// Output: 65533
在前面的示例中, signed short 将 i 定义,并将其初始化为负数。 表达式 (u = i) 导致在 i 赋值之前将转换为 unsigned short u 。
无符号转有符号
- 无符号整数类型的对象可以转换为对应的有符号类型。
- 但是,如果无符号值不在已签名类型的可表示范围内,则结果将不具有正确的值,如以下示例中所示:
#include <iostream>
using namespace std;
int main()
{
short i;
unsigned short u = 65533;
cout << (i = u) << "\n";
}
//Output: -3
在前面的示例中, u 是一个 unsigned short 整数对象,必须将其转换为有符号的数量,才能计算表达式的值 (i = u) 。 由于不能在中正确表示其值 signed short ,因此会将数据解释为显示的错误。
凡在语境中使用了某种表达式类型T1,但语境不接受该类型,而接受另一类型T的时候,会进行隐式转换,具体是:
- 调用以T2为形参声明的函数,以该表达式为实参
- 运算符期待 T2,而以该表达式为操作数;
- 初始化 T2 类型的新对象,包括在返回 T2 的函数中的 return 语句
- 将表达式用于 switch 语句(T2 为整型类型);
- 将表达式用于 if 语句或循环(T2 为 bool)。
例子:自定义类型到标量类型的转换:
std::shared_ptr<int> ptr = func();
if (ptr) { // 这里会从shared_ptr转换成bool
// 处理数据
}
由于提供了用户自定义的隐式类型转换规则,因此咱们能够很简单地去判断智能指针是否为空。在这里if表达式里须要bool,所以ptr转换为了bool,这又被叫作语境转换。
仅当存在一个从 T1 到 T2 的无歧义隐式转换序列时,程序良构(能编译)。
如果所调用的函数或运算符存在多个重载,则将T1到每个可用的T2都构造隐式转换序列之后,以重载决议规则决定编译哪个重载
转换序列
- 当考虑构造函数或用户定义转换函数的实参时,只允许一个标准转换序列(否则将实际上可以将用户定义转换串连起来)