C++中四种强制类型转换:static_cast, reinterpret_cast, const_cast, dynamic_cast
1. static_cast(编译时类型检查)
用于非多态类型之间的转换(静态转换),任何标准类型之间都可以用它,但它不能用于不相关类型之间的转换。主要有以下几种用法:
- 用于基本的数据类型之间的转换,例如把int转换为char,把int转换为enum,但这种转换的安全性需要开发者自己保证,static_cast所做的只是简单的截断;
- 空指针转换成目标类型的空指针;
- 任何类型的表达式转换成void类型;
- 用于层次结构中父类和子类之间指针和引用的转换;
对于第4点,存在两种形式的转换,上行转换(子类到父类),下行转换(父类到子类);对于static_cast,从子类到父类的转换是安全的,因为子类包含了父类的所有数据成员和函数成员,从子类转换到父类的指针对象可以没有任何顾虑的访问其成员;而对于从父类到子类的转换,因为static_cast是在编译时进行类型检测,没有运行时的类型检查,是不安全的。
void Test()
{
double i = 2;
int d = static_cast<int>(i);
printf("%lf, %d\n", i, d);
}
2. dynamic_cast(运行时类型检查)
主要用于类层次结构中父类和子类之间指针和引用的转换,由于具有运行时类型检查,可以保证下行转换(父类到子类)的安全性,即:转换成功就返回转换后的正确类型指针,如果失败,返回NULL;而static_cast如果失败,不会返回NULL,所以不安全。
总结为以下两句:
- 对于上行转换,从子类到父类的转换,子类的指针指向的是子类对象,一般不会指向父类对象,所以static_cast和dynamic_cast效果一样;
- 对于下行转换,从父类到子类的转换,如果父类的指针指向的是父类对象,那么static_cast就会不安全,而dynamic_cast在运行时检查过程中,判定不能转换,返回NULL;如果父类的指针指向子类对象,那么两个也都能成功。
class Base
{
virtual void fun()
{}
};
class Derived :public Base
{
};
void Test()
{
Derived* pb = new Derived; // 子类转父类
Base* pb1 = static_cast<Base*>(pb);
Base* pb2 = dynamic_cast<Base*>(pb);
Base *p1 = new Derived; // 父类转子类,父类指针指向子类对象
Derived *pd1 = static_cast<Derived *>(p1);
Derived *pd2 = dynamic_cast<Derived *>(p1);
Base *p2 = new Base; // 父类转子类,父类指针指向父类对象
Derived *pd3 = static_cast<Derived *>(p2); // 不安全
Derived *pd4 = dynamic_cast<Derived *>(p2); //pd4 = NULL;
}
3. reinterpret_cast
用于将一种类型转换为另一种不同的类型。用于底层的强制类型转换,导致实现依赖的结果(不可移植),例如:将一个指针转换为整数。
typedef void(*FUNC)();
int DoSomething(int i)
{
cout << "DoSomething" << endl;
return 0;
}
void Test()
{
FUNC f = reinterpret_cast<FUNC>(DoSomething);
f();
int i = 0;
int p = reinterpret_cast<int>(&i);//将指针转换为整数
}
4. reinterpret_cast
删除变量的const属性,方便赋值。
void test()
{
const int a = 5;
int* pa = const_cast<int *>(&a);
*pa = 10;
cout << a << endl; //打印的结果还是5,由内存窗口可以看到值已经被改,因为编译器优化,到寄存器中取值
cout << *pa << endl; //结果是10,pa指向内存中的a,改的是内存中的值
}
void test()
{
volatile const int a = 5;
int* pa = const_cast<int *>(&a);
*pa = 10;
cout << a << endl; //打印的结是10,被volatile修饰,从内存中读取数据,解锁是10
cout << *pa << endl;
}