简介:
C++还提供了reinterpret_cast用于任意类型的转换,即reinterpret_cast运算符允许将任意指针转换到其他指针类型,也允许做任意整数类型和任意指针类型之间的转换。转换时,执行的是逐个比特复制的操作。reinterpret中文意为“重新解释; 重新诠释;”。
reinterpret_cast使用注意事项:
从本质上说所有这些转换都是不安全的,依赖于实现的,或两者都是, reinterpret也不例外(存在安全性)。这种安全性只能由程序员自己来保证。
数据类型转换系列文章:
reinterpret_cast使用举例:
reinterpret_cast的用法:
reinpreter_cast<type-id> (exp)
其中, reinterpret_cast后的尖括号中的type-id类型必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。
例1:普通类型的转换,类类型的转换演示:
#include <iostream>
#include <typeinfo>
using namespace std;
class A {
public:
int a;
void fun1() {cout<<"A::fun1"<<endl;}
};
class B{
public:
int b;
void fun2() {cout<<"B::fun2"<<endl;}
};
void test_fun(int* pi,char* pc,A* pA,B* pB,int i) {
char* pc2 = reinterpret_cast<char*>(pB);
int* pi2 = reinterpret_cast<int*>(pc);
int* pi3 = reinterpret_cast<int*> (i);
A* pA2 = reinterpret_cast<A*>(pi);
A* pA3 = reinterpret_cast<A*>(pB);
long i2 = reinterpret_cast<long>(pA2);
cout<<"i2="<<i2<<endl; //i2=140732900210728
pA2->fun1(); //输出: A::fun1
pA3->fun1(); //输出: A::fun1
A a;
B b;
//B b2 = reinterpret_cast<B>(a); //error: reinterpret_cast from 'A' to 'B' is not allowed
//A a2 = reinterpret_cast<A>(b); //error: reinterpret_cast from 'B' to 'A' is not allowed
//pA3->fun2(); //no member named 'fun2' in 'A'; did you mean 'fun1'?。虽然pB是B类型的指针,但是,pA3的类型是指向A的指针。
}
int main()
{
int i = 10;
int *pi = &i;
char *ch = "hello";
A a;
B b;
test_fun(pi,ch,&a,&b,i);
return 0;
}
/*
编译环境:mac os下用g++编译:
*/
例2:在继承体系中:
#include <iostream>
#include <typeinfo>
using namespace std;
class A {
public:
int a;
void fun1() {cout<<"A::fun1"<<endl;}
};
class B{
public:
int b;
void fun2() {cout<<"B::fun2"<<endl;}
};
class D: public A, public B {
void fun4() {cout<<"D::fun4"<<endl;}
};
void test_fun(B* pb) {
D* pd1 = reinterpret_cast<D*>(pb); //warning: 'reinterpret_cast' to class 'D *' from its base at non-zero offset 'B *' behaves differently from 'static_cast' [-Wreinterpret-base-class]
//note: use 'static_cast' to adjust the pointer correctly while downcasting
D* pd2 = static_cast<D*>(pb);
}
int main()
{
D d;
test_fun(&d);
return 0;
}
/*
编译环境:mac os下用g++编译:
*/
可见,虽然能正常编译,但是,g++编译器还是给出了warning。
上面的代码中,
D* pd1 = reinterpret_cast<D*> (pb);
D* pd2 = static_cast<D*>(pb);
在典型情况下,这里pd1和pd2将得到不同的值。pd2将指向传递来的D对象的开始位置,而pd1将指向该p对象的B子对象的开始。
reinterpretcast绝不在类层次中穿行,不会强制去掉const。
例3:转换为指针函数:
void thump(char* p){ *p = 'x';}
typedef void (*PF)(const char*);
PF pf;
void g (const char* pc){
//thump (pc);// error: no matching function for call to 'thump',因为参数类型错误
//pf = &thump; // error: incompatible function pointer types assigning to 'PF'
//pf = static_cast<PF>(&thump);// error: static_cast from 'void (*)(char *)' to 'PF' (aka 'void (*)(const char *)') is not allowed
pf = reinterpret_cast<PF>(&thump); // ok: on your head be it
pf(pc);// not guaranteed to work!
}
int main()
{
char* str = "h";
g(str);
return 0;
}
/*
编译环境:mac os下用g++编译:
*/
很清楚,让pf去指向thump是很危险的,因为这样做就是想欺骗类型系统,使它能允许将一个常量的地址传到某个要修改它的地方去。这也就是为什么我们必须使用强制的地方。
reinterpret_cast和static_cast的比较:
static_cast就是利用C++类型之间的继承关系图和聚合关系图(编译器必须知道),根据一个子对象地址计算另一个子对象的地址。
reinterpret_cast不关心继承关系,直接把数据类型A的地址解释成另一个数据类型B的地址。
所以,对于无继承关系的类的转换,static_cast需要进行构造函数的重载,参数必须是要被转换的类的类型。而reinterpret_cast则没有这个限制。
例如,对于
class A {};
class B {}
void test_fun() {
A a;
B *pB1 = reinterpret_cast<B*>(&a);
}
是正确的,而,
B b1 = static_cast<B>(a);
是错误的,错误信息如下:
error: no matching conversion for static_cast from 'A' to 'B'
candidate constructor (the implicit copy constructor) not viable: no known conversion from 'A' to 'const B' for 1st argument
如果将B类的定义改为:
class B{
public:
B(A& a) {}
};
则,
B b1 = static_cast<B>(a);
就是正确的。
总结:
1)reinterpret_cast并不在类的层次中穿行,即不关心继承体系;
2)reinterpret_cast用于任意类型的转换,当然,和其它强制转换一样,存在安全性;
3) reinterpret_cast不会强制去掉const;
4)reinterpret_cast后的尖括号中的类型必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。