C++:类型转换(static_cast、reinterpret_cast、const_cast、dynamic_cast)、RTTI
- 一、C语言类型转换
- 二、C++新增强制类型转换
- 2.1 新增类型转换:static_cast
- 2.2 新增类型转换: reinterpret_cast
- 2.3 新增类型转换:const_cast
- 2.4 新增类型转换:dynamic_cast
- 三、 什么是RTTI ?
一、C语言类型转换
在C中支持类型转换, 分为隐式类型转换和显示类型转换。但C中类型转换不是非常规范不规范,存在以下问题:
- 隐式类型转换:编译器在编译阶段自动转换。如果不能转换,编译失败。
- 显示类型转换:用户自己处理。
二、C++新增强制类型转换
由于C语言两种类型转换方式都存在缺陷:隐式类型转换会导致诸如数据精度丢失等问题;而显示类型转化代码不清晰。所以C++在兼容C的基础之上,增加了4中强制类型转换:static_cast、reinterpret_cast、const_cast、dynamic_cast。
2.1 新增类型转换:static_cast
static_cast
用于非多态的类型的转化,即静态转化。static_cast
和C中的隐式类型转换类似,编译器会自动进行类型转换。如果不能转换,则编译失败!
int main()
{
double d = 123.12l;
int i = static_cast<int>(d);
return 0;
}
2.2 新增类型转换: reinterpret_cast
reinterpret_cast
对标的是C中的显示类型转换。需要注意的是显示类型转换通常会伴随风险,使用reinterpret_cast
不会进行类型安全检查。
int main()
{
int i = 3;
//int* p = static_cast<int*>(i); //error
int* p = reinterpret_cast<int*>(i);
return 0;
2.3 新增类型转换:const_cast
const_cast
用于去除变量的const
属性,使变量能够进行赋值操作。
【实例】:
int main()
{
const int i = 2;
int* p = const_cast<int*>(&i);//删除常变量i的const属性
(*p)++;
//cout << i << ":" << *p << endl;
printf("i=%d, *p=%d\n", i, *p);
return 0;
}
- 既然我们已经使用
const_cast
删除了变量i
的const
属性,为什么这里i的结果认为2? - 原因在于编译器的优化。当一个变量为const属性时,编译器认为该变量不在被修改,所以会用一个寄存器直接保存该变量的结果;或者在编译阶段直接类似宏替换,将i替换为2。
所以我们可以通过关键字volatile
禁止编译器对常变量的优化!!
int main()
{
volatile const int i = 2;
int* p = const_cast<int*>(&i);//删除常变量i的const属性
(*p)++;
//cout << i << ":" << *p << endl;
printf("i=%d, *p=%d\n", i, *p);
return 0;
}
- 这里输出时不要用cout。原因在于这里使用
volatile
后,由于C++标准输出库存在缺陷,没有匹配到正确的重载函数。
2.4 新增类型转换:dynamic_cast
dynamic_cast
用于动态转换,将一个父类对象的指针或引用转换为一个子类对象的指针或引用。
- 向上转换:子类对象指针/引用->父类指针/引用(我们认为该过程是天然的,不产生临时变量。通过赋值兼容规则(切片)直接将子类对象指针/引用给父类指针/引用)
- 向下转换:父类指针/引用->子类对象指针/引用。这种情况下,如果直接强转类型,可能回到住越界访问的风险。而
dynamic_cast
则可以避免该问题。(具体看实例)
tips:
- dynamic_cast只能用于父类含有虚函数的类!!
dynamic_cast
会先检查能否转换成功。如果能成功,则进行转换。否则返回一个空指针!!
void func(A* pa)
{
//不安全, 原因在于如果是一个A类型的指针转递给pa,此时后续访问_b是发生越界访问
//B* ptr = (B*)pa;
//使用dynamic_cast,如果将A类型的指针转递给pa会转换失败,返回空指针
//而将B类型的指针转递给pa, 转换成功,恢复到原始状态
B* ptr = dynamic_cast<B*>(pa);
if (ptr)
{
ptr->_a++;
ptr->_b++;
cout << ptr->_a << ":" << ptr->_b << endl;
}
else
{
cout << "转换失败" << endl;
}
}
int main()
{
A a;
B b;
cout << "B b -> func(&a):" << endl;
func(&a);//转换失败
cout << endl;
cout << "A a -> func(&b):" << endl;
func(&b);
return 0;
return 0;
}
三、 什么是RTTI ?
RTTI:Run-time Type identification的简称,即:运行时类型识别。C++通过以下方式来支持RTTI:
- typeid运算符
- dynamic_cast运算符
- decltype