C/C++编程:类型转换

如果表达式包含不同内置类型的操作数,并且不存在显式强制转换,则编译器将使用内置的标准转换来转换其中一个操作数,使这些类型匹配。

编译器将尝试按一个明确定义的顺序进行转换,直到有一个转换成功。

  • 如果所选转换是提升转换,则编译器不会发出警告
  • 如果转换是是收缩转换,则编译器会发出有关数据可能丢失的警告。( 尽管是否真的发生数据丢失取决于涉及的实际值,但我们建议您将此警告视为错误。)

我们来看个例子:混用数值类型的转换

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都构造隐式转换序列之后,以重载决议规则决定编译哪个重载

转换序列

  • 当考虑构造函数或用户定义转换函数的实参时,只允许一个标准转换序列(否则将实际上可以将用户定义转换串连起来)

完全理解c++的隐式类型转换