1.隐式类型转换
系统自动进行,不需要程序开发人员介入。
int n = 3 + 45.6;
cout << n << endl; // 48
double m = 3 + 45.6;
cout << m << endl; // 48.6
2.显式类型转换(强制类型转换)
2.1 C语言
格式:(type)expression
或 type(expression)
int n = 5 % (int)3.2;
cout << n << endl; // 2
int m = 5 % int(3.2);
cout << m << endl; // 2
2.2 C++语言
C++ 强制类型转换分为 4 种,这 4 种强制类型转换分别用于不同的目的,每一种都有一个不同的名字,提供了更丰富的含义和功能、更好的类型检查机制,方便代码的书写和维护。
格式:强制类型转换名<type>(expression)
,其中 type
是要转成的目标类型,expression
是待转换的值。
2.2.1 static_cast
编译的时候就会进行类型转换的检查,代码中要保证转换的安全性与正确性,没有运行时安全检查。
static_cast 可以理解为“正常转换”,其含义跟 C 语言中的强制类型转换差不多。
2.2.1.1 可用于
(1) 相关类型转换,比如整型和实型之间的转换。
double f = 100.98;
int n = (int)f;
cout << n << endl; // 100
int m = static_cast<int>(f);
cout << m << endl; // 100
(2) 子类类型转换为父类类型。
class A {};
class B : public A {};
B b;
A a = static_cast<A>(b);
(3) void *
与其他类型指针之间的转换。
int i = 10;
int* p1 = &i;
void* q = static_cast<void*>(p1);
int* p2 = static_cast<int*>(q);
2.2.1.2 不可用于
(1) 一般不能用于指针类型之间的转换,比如 int *
转 double *
、float *
转 double *
等。
#include <iostream>
using namespace std;
int main()
{
double num = 100.0f;
double* p1 = #
int* p2 = static_cast<int*>(p1); // 不可以
float* p3 = static_cast<float*>(p1); // 不可以
return 0;
}
(2) 不能交叉转换,即不是同一继承体系的无法转换。
2.2.2 dynamic_cast
运行时类型识别与检查。
主要用于父类型和子类型之间的转换,即父类型指针指向子类型对象,然后用 dynamic_cast 把父指针类型转换为子指针类型。
2.2.3 const_cast
编译时类型转换。
用于去除指针或者引用的 const 属性。
#include <iostream>
using namespace std;
int main()
{
const int n = 90;
const int* p1 = &n;
int* p2 = const_cast<int*>(p1); // 语法正确
*p2 = 120; // 虽然语法上没问题,但这种赋值行为是一种未定义行为,不建议
cout << n << endl;
cout << *p1 << endl;
cout << *p2 << endl;
cout << &n << endl;
cout << p1 << endl;
cout << p2 << endl;
return 0;
}
从下图中可以看出,n
仍然保留着原来的值 90
,但是它们的确指向了同一个地址,这真是一件奇怪的事情!不过,这是一件好事:说明 C++ 里是 const 就是 const,外界千变万变,我就不变,不然真的就乱套了,const 也就没有存在的意义了。
未定义行为(Undefined Behavior)就是这个语句在标准 C++ 中没有明确的规定,由编译器来决定如何处理。
2.2.4 reinterpret_cast
编译时类型转换。
reinterpret_cast
运算符用来处理无关类型之间的转换,它会产生一个新的值,这个值与原始参数 expressoin
有完全相同的比特位。
reinterpret
意思是“重新解释”,即将操作数内容解释为另一种不同的类型,属于比较底层的强制转换,没有任何类型检查和格式转换,仅仅是简单的二进制数据拷贝。
-
可以交叉转换
-
任意指针或引用类型之间的转换
-
从指针类型到一个足够大的整数类型
-
从整数类型或枚举类型到指针类型
#include <iostream>
using namespace std;
int main()
{
int n = 90;
int* p1 = &n;
void* p2 = reinterpret_cast<void*>(p1);
int* p3 = reinterpret_cast<int*>(p2);
return 0;
}
reinterpret_cast
可以乱转、自由转,被认为是危险的类型转换,但只要好好用、合乎规则地用,其实 reinterpret_cast
也很好用。