一. static_cast
static_cast基于内容转换,相对安全。
1.普通用法
int i = 2;
float f = static_cast(i); //类似float f=(float)(i);
2.void* 转换
任何指针都能隐式转换为void*,然而,要对void*指向的对象进行操作,必须先将void*转换为具体类型的指针,而且必须是显式转换,不允许隐式转换。例如:
int i = 2;
void *vp = &i;
//cout<<*vp<(vp);
//也可以用 int *ip = reinterpret_cast(vp);
//也可以用 int *ip = (int*)(vp);
cout<<*ip<
3.基类向派生类的转换及其安全性问题
根据C++类型兼容规则,派生类对象、指针、引用可以隐式转换为基类,但是基类指针、引用转派生类,则要显式地进行。
Base *pb = new Derived(); //隐式转换
Derived *pd = static_cast(pb); //显式转换
Derived d;
Base &rb = d; //隐式转换
Derived &rd = static_cast(rb); //显式转换
(1). 基类对象一般无法被显式转换为派生类对象,也就是说,下面的写法是不合法的,除非Derived类有接收Base类型(或它的引用类型)参数的构造函数。
Base b;
Derived d = static_cast(b);
(2). 执行基类向派生类转换时,一定要确保被转换的指针和引用所指向或引用的对象符合转换的目的类型。在下面的转换中:
Derived *pd = static_cast(pb);
一定要保证pb指向的对象具有Derived类型,或者是Derived的派生类。
Base *pb = new Base();
Derived *pd = static_cast(pb); //编译错误
(3). 在多重继承情况下,执行基类指针到派生类指针的显式转换时,有时候需要将指针所存储的地址值进行调整后才能得到新指针的值
(4). 如果指针转换涉及void*,即使最初的指针类型和最后的指针类型是兼容的,但只要最初和最后的类型不完全相同,转换的结果就可能是不正确的。
Derived *pd = new Derived();
void *pv = pd;
Base *pb = static_cast (pv);
这一转换结果,与直接将pd转换为Base指针的结果是不一样的。因为正确的转换中,将pd转换为Base指针,需要在原地址上增加一个偏移量,但这里的每步转换都涉及void指针,这个偏移量始终没有加上。
这提醒我们,使用void*时,前后的类型一定要严格相同。
二. const_cast
const_cast可以用来将数据类型中的const属性去除,将常指针转换为普通指针,或将常引用转换为普通引用。const_cast不用来将常对象转换为普通对象,这是没有意义的,因为对象的转换会生成对象的副本。const_cast是不安全的,而相对安全的static_cast不具备去除const的功能。
void foo(const int* cp){
int *p = const_cast(cp);
(*p)++;
}
三. reinterpret_cast
reinterpret_cast将一种类型的指针转换成另一种类型的指针,有很大的危险性和不确定性,一般只用于帮助一些非常底层的操作。看以下代码输出。
int i = 2;
float *p = reinterpret_cast(&i); //也可以用float *p = (float*)(&i);
//float *pf = static_cast(&i);//编译错误
//*p = 2.1;
cout<
输出为:
2, 2.8026e-45
2, 0.000000
四. dynamic_cast
dynamic_cast执行基类的指针显示转换为派生类的指针,或将基类的引用显示转换为派生类的引用。这里的基类和派生类必须是属于多态类型的,dynamic正是多态、动态的意思。但与static_cast不同的是,dynamic_cast执行的是有条件的转换,转换前会检查指针或引用所指向对象的实际类型是否与转换的目的类型兼容。如果兼容转换才会执行成功,得到派生类的指针或引用,否则:
- 如果执行的是指针类型的转换,会得到空指针;
- 如果执行的是引用类型的转换,会抛出异常。
执行基类向派生类转换,dynamic_cast 比 static_cast更安全,但是要付出一定的效率代价。
#include
using namespace std;
class Base{
public:
virtual ~Base(){}
virtual void fun1(){ cout<<"Base::fun1()"<fun1();
Derived1 *d=dynamic_cast(b);
if (d != NULL)
d->fun2();
}
int main(){
Base b;
fun(&b);
Derived1 d1;
fun(&d1);
Derived2 d2;
fun(&d2);
return 0;
}
输出如下:
Base::fun1()
Derived1::fun1()
Derived1::fun2()
Derived2::fun1()
Derived2::fun2()