我对reinterpret_cast和static_cast的适用性有点困惑。根据我所读到的,一般规则是当类型可以在编译时解释时使用静态强制转换,因此是静态这个词。这也是c++编译器内部用于隐式类型转换的类型转换。

reinterpret_cast适用于以下两种情况:

将整数类型转换为指针类型,反之亦然 将一种指针类型转换为另一种。我得到的一般想法是,这是不可移植的,应该避免。

我有点困惑的地方是我需要的一种用法,我从C调用c++, C代码需要保持c++对象,所以基本上它持有一个void*。在void *和Class类型之间应该使用什么类型转换?

我已经看到使用static_cast和reinterpret_cast?虽然从我所读到的似乎静态更好,因为强制转换可以在编译时发生?虽然它说使用reinterpret_cast从一种指针类型转换为另一种?


当前回答

可以在编译时使用reinterprete_cast检查继承。 看这里: 在编译时使用reinterpret_cast检查继承

其他回答

reinterpret_cast的一个用途是如果你想对(IEEE 754)浮点应用位操作。其中一个例子是快速平方根逆技巧:

https://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code

它将浮点数的二进制表示形式视为整数,将其右移并从常数中减去,从而将指数对半和负。在转换回浮点数后,它会进行牛顿-拉弗森迭代,以使这个近似更加精确:

float Q_rsqrt( float number )
{
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y;                       // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );               // what the deuce? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );   // 1st iteration
//  y  = y * ( threehalfs - ( x2 * y * y ) );   // 2nd iteration, this can be removed

    return y;
}

它最初是用C语言编写的,所以使用C类型强制转换,但类似的c++类型强制转换是reinterpret_cast。

reinterpret_cast的含义不是由c++标准定义的。因此,理论上reinterpret_cast可能导致程序崩溃。在实践中,编译器试图做你所期望的事情,也就是解释你传入的二进制位,就好像它们是你要强制转换的类型一样。如果你知道你将要使用的编译器对reinterpret_cast做了什么,你就可以使用它,但是说它是可移植的是在撒谎。

对于您所描述的情况,以及您可能会考虑reinterpret_cast的大多数情况,您可以使用static_cast或其他替代方法。在其他事情中,标准有这样说你可以期待static_cast(§5.2.9):

类型为“指向cv void的指针”的右值可以显式转换为指向对象类型的指针。一个类型为pointer to object的值转换为" pointer to cv void "并返回到原始指针类型将有其原始值。

因此,对于您的用例,标准化委员会显然希望您使用static_cast。

下面是Avi Ginsburg程序的一个变体,它清楚地说明了Chris Luengo、flodin和cmdLP提到的reinterpret_cast属性:编译器将指向内存的位置视为新类型的对象:

#include <iostream>
#include <string>
#include <iomanip>
using namespace std;

class A
{
public:
    int i;
};

class B : public A
{
public:
    virtual void f() {}
};

int main()
{
    string s;
    B b;
    b.i = 0;
    A* as = static_cast<A*>(&b);
    A* ar = reinterpret_cast<A*>(&b);
    B* c = reinterpret_cast<B*>(ar);
    
    cout << "as->i = " << hex << setfill('0')  << as->i << "\n";
    cout << "ar->i = " << ar->i << "\n";
    cout << "b.i   = " << b.i << "\n";
    cout << "c->i  = " << c->i << "\n";
    cout << "\n";
    cout << "&(as->i) = " << &(as->i) << "\n";
    cout << "&(ar->i) = " << &(ar->i) << "\n";
    cout << "&(b.i) = " << &(b.i) << "\n";
    cout << "&(c->i) = " << &(c->i) << "\n";
    cout << "\n";
    cout << "&b = " << &b << "\n";
    cout << "as = " << as << "\n";
    cout << "ar = " << ar << "\n";
    cout << "c  = " << c  << "\n";
    
    cout << "Press ENTER to exit.\n";
    getline(cin,s);
}

结果是这样的输出:

as->i = 0
ar->i = 50ee64
b.i   = 0
c->i  = 0

&(as->i) = 00EFF978
&(ar->i) = 00EFF974
&(b.i)   = 00EFF978
&(c->i)  = 00EFF978

&b = 00EFF974
as = 00EFF978
ar = 00EFF974
c  = 00EFF974
Press ENTER to exit.

可以看到,B对象首先作为特定于B的数据构建在内存中,然后是嵌入的A对象。static_cast正确地返回嵌入的A对象的地址,并且由static_cast创建的指针正确地给出data字段的值。由reinterpret_cast生成的指针将b的内存位置视为普通的a对象,因此当指针试图获取数据字段时,它将返回一些特定于b的数据,就像它是该字段的内容一样。

reinterpret_cast的一个用途是将指针转换为无符号整数(当指针和无符号整数大小相同时):

int我; Unsigned int u = reinterpret_cast< Unsigned int>(&i);

阅读FAQ!在C语言中保存c++数据是有风险的。

在c++中,指向对象的指针不需要任何类型转换就可以转换为void *。但反过来就不是这样了。您需要一个static_cast来取回原始指针。

可以在编译时使用reinterprete_cast检查继承。 看这里: 在编译时使用reinterpret_cast检查继承