简介: 

C++还提供了reinterpret_cast用于任意类型的转换,即reinterpret_cast运算符允许将任意指针转换到其他指针类型,也允许做任意整数类型和任意指针类型之间的转换。转换时,执行的是逐个比特复制的操作。reinterpret中文意为“重新解释; 重新诠释;”。

reinterpret_cast使用注意事项:

从本质上说所有这些转换都是不安全的,依赖于实现的,或两者都是, reinterpret也不例外(存在安全性)。这种安全性只能由程序员自己来保证。

 数据类型转换系列文章:

C++中的动态强制dynamic_cast

C++中的RTTI机制之typeid

C++中的静态强制static_cast

C++中的reinterpret_cast数据类型转换

C++中的const_cast数据类型转换

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后的尖括号中的类型必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针。


Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐