目录
1.C语言中的类型转换
在C语言中,如果赋值运算符左右两侧类型不同,或者形参与实参类型不匹配,或者返回值类型与 接收返回值类型不一致时,就需要发生类型转化,C语言中总共有两种形式的类型转换:隐式类型转换和显式类型转换。
1. 隐式类型转化:编译器在编译阶段自动进行,能转就转,不能转就编译失败
2. 显式类型转化:需要用户自己处理
比如:
//隐式类型转换(只能是相近类型)
int a = 10;
double b = a;
char c = 'a';
bool i = c > a;//整形提升
c = a;//这里的 数据截断 是隐式转换
//显示类型(强制类型)转换
size_t d = (size_t) &a;
a = (int)b;
c = (char)a;//这里的 数据截断 是强制转换
int* p = (int*)a;
缺陷: 转换的可视性比较差,所有的转换形式都是以一种相同形式书写,难以跟踪错误的转换 ;有些场景还会造成 精度丢失 等问题。
因此C++提出了自己的类型转化风格,其实就是规范化了这一操作。
2.C++强制类型转换操作符
2.1 static_cast
用于非多态类型的转换,也叫静态转换,编译器隐式执行的任何类型转换都可用 static_cast。
int a = 10;
double b = static_cast<double>(a);
char c = 'a';
bool i = static_cast<int>(c) > a;//整形提升
c = static_cast<char>(a);//数据截断
2.2 reinterpret_cast
通常为操作数的位模式提供较低层次的重新解释,即:并不改变数据的实际位模式,
而是直接将数据的二进制表示重新解释为另一种类型。
int a = 10;
char c = 'c';
size_t d = reinterpret_cast<rsize_t>(&a);
int* p = reinterpret_cast< int*>(a);
p = reinterpret_cast<int*>(&c);
//错误示例:二进制位数不同
//c = reinterpret_cast<char>(a);
这种转换通常用于底层编程,需要开发者确保转换的安全性,因为reinterpret_cast不会进行任何类型检查。
2.3 const_cast
最常用的用途就是删除变量的const属性,方便赋值。
const int a = 2;
int* p = const_cast< int*>(&a );
*p = 3;
2.4 dynamic_cast
用于将一个父类对象的指针/引用转换为子类对象的指针或引用(动态转换)
向上转型:子类对象指针/引用->父类指针/引用(不需要转换,赋值兼容规则)
向下转型:父类对象指针/引用->子类指针/引用(用dynamic_cast转型是安全的)
注意:
1. dynamic_cast只能用于父类含有虚函数的类
2. dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
class A
{
public:
virtual void f() {}
};
class B : public A {};
void fun(A* pa)
{
B* pb1 = static_cast<B*>(pa);//不构成多态
B* pb2 = dynamic_cast<B*>(pa);
cout << "pb1:" << pb1 << endl;
cout << "pb2:" << pb2 << endl;
}
int main()
{
A a;
B b;
fun(&a);
fun(&b);
return 0;
}
示例输出:
注意: 强制类型转换关闭或挂起了正常的类型检查,每次使用强制类型转换前,应该仔细考虑是 否还有其他不同的方法达到同一目的,如果非强制类型转换不可,则应限制强制转换值的作用 域,以减少发生错误的机会。(建议:避免使用强制类型转换)
3.RTTI
Run-time Type identification的简称,即:运行时类型识别。
C++通过以下方式来支持RTT1:
typeid
运算符:用于获取对象的类型信息,返回一个type_info
对象。dynamic_cast
运算符:用于在类层次结构中进行安全的向下转换(downcasting)。decltype
:虽然decltype
主要用于在编译时获取表达式的类型,但它也可以在某些情况下与RTTI结合使用。
RTTI在处理复杂的类层次结构和动态类型时非常有用,但也可能会影响性能,因此应谨慎使用。