强制类型转换运算符:
强制类型转换有一定的风险,有的转换并不一定安全。如把整型转换成整型指针,把基类指针转换成派生类指针,把一个函数指针转换成另一种函数指针,把常量指针转换成非常量指针等。
C语言强制类型转换的缺点:
- 转换太过随意,可以在任意类型之间转换。
如,将int转double是没有风险的,而将const指针转非const指针,基类指针转派生类指针都是高风险。 - 没有统一的关键字和标示符。对于大型系统,做代码排查时容易遗漏和忽略。
- 将多态基类指针转换成派生类指针时不检查安全性。
C++引入了四种功能不同的强制类型转换运算符:
- const_cast
- static_cast
- dynamic_cast
- reinterpret_cast
1. const_cast - 去const属性
去掉类型的const或者volatile属性。只针对指针,引用,包括this指针。
用例:
const成员函数中(函数声明后加const, 表示该函数不能修改成员变量的值),去除this指针的常成员属性。示例:
const int val = 10;
int &v= const_cast <int&> (val); // 用于引用。
int *p = const_cast <int*> (&val); // 用于指针
//用于去成员函数const属性
class CTest
{
public:
int a;
void foo(int val) const
{
//this->a = val;//非法,常成员函数不能修改成员变量的值。 /*this指针其实是 const CTest*const this
可以使用const_cast关键字去除this指针前面的const属性。*/
const_cast<CTest*const>(this)->a = val; //仅去掉指针前面的const属性,允许指针指向的内容被修改。合法
const_cast<CTest*>(this)->a = val; //掉指针全部const属性,允许指针指向的内容和指针被修改。编译合法,但是最后不要修改this.
return a;
};
}
tips:
//常量指针:const在*前面
const int *a; int const *a;//a指向的内容不变,指针指向的内容是常量,*a=123;// 非法
//指针常量:const在*后面
int *const a;//a不能重新指向新的地址,指针是常量 a=&b;// 非法
2.static_cast — 用来明确隐式转换,多用于基本数据类型转换
类似C风格的强制类型转换,编译时检查,用于非多态的转换,可以转换指针及其他,但没有运行时类型检查来保证转换的安全性。
- 可以用于基类和子类之间的转换
子类指针转父类是安全
父类转子类指针是不安全的(建议用dynamic_cast) - 用于基本数据类型转换,enum,struct,int,char,float等。static_cast不能进行无关类型(如非基类和子类)指针之间的转换。
- 把任何类型的表达式转换成void类型。
- static_cast不能去掉类型的const、volatile属性(要用const_cast)
3.dynamic_cast: – 仅用在多态 (依赖RTTI, 有额外的开销)
dynamic_cast用于具有虚函数的基类和派生类之间的指针或引用的转换。
基类必须具备虚函数
原因:dynamic_cast是运行时类型检查,需要运行时的类型信息(RTTI,run time type identify),而这个信息和类的虚函数表关系紧密。
如果没有,编译不通过,会提示不是多态类型
dynamic_cast 是通过“运行时类型检查”来保证安全性的,对于不安全的指针转换,转换结果返回 NULL 。不能用于将非多态基类的指针或引用强制转换为派生类的指针或引用——这种转换没法保证安全性,可用 reinterpret_cast 来完成。
常见的转换方式:
- 基类指针或引用转成派生类指针或引用(必须使用dynamic_cast)。
- 派生类指针或引用转成基类指针或引用(可以使用dynamic_cast,但是更推荐static_cast,节省资源)
要点:
- 相同基类不同子类之前的交叉转换,结果返回NULL。因此,可以通过返回值是否是NULl来确定具体的子类类型。
- 运行时才能知道是否转换成功。
- 非必要,不使用dynamic_cast,有额外的函数开销。
4.reinterpret_cast 强制转换(类似C显式强转)
reinterpret_cast 用于进行各种不同类型的指针之间、不同类型的引用之间以及指针和能容纳指针的整数类型之间的转换。转换时,执行的是逐个比特复制的操作
- 仅重新解释类型,但没有进行二进制的转换:
- 在比特级别上进行转换,可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。但不能将非32bit的实例转成指针。
- 最普通的用途就是在函数指针类型之间进行转换。
- 很难保证移植性。
- 编译器处理,执行的是逐字节复制的操作。
- 类似于显式类型转换,后果自负。