为什么我需要reinterpret_cast将Fred ** const转换为void ** const?

时间:2012-07-10 09:55:06

标签: c++ void-pointers reinterpret-cast static-cast

我有一个指针指向Fred的const指针,我不明白为什么static_cast是不够的。

typedef struct {
    int n;
} Fred;

Fred *pFred;
Fred **const ppFred = &pFred;
void **const ppVoid = static_cast<void ** const>(ppFred);

请有人解释为什么需要reinterpret_cast将指针转换为Fred*指针指向void*,但static_cast可以将指针转换为{{1}指向Fred的指针。

4 个答案:

答案 0 :(得分:12)

不要求Fred*void*具有相同的尺寸 和代表。 (我曾在他们没有的机器上工作, 虽然那是在我的C ++日之前。)当你将Fred*转换为 void*,你得到一个新的指针,可能有不同的大小和 表示,但没有关于大小和信息的信息 void*指向的对象的表示。你知道它是 未知,使用此void*的唯一方法是将其强制转换为 Fred*(模块化的事物,如cv-qualifiers)。转换Fred**时 到void**,你将指针转换为具体类型(a 指向Fred*的指针指向另一个具体类型的指针(指针 到void*)。而且由于不能保证这两个具体 类型具有相同的大小和表示,转换需要a reinterpret_castvoid是一种特殊的,非具体的类型,所以你可以 static_cast指向void指针的任何类型的指针。 void*只是另一种具体的指针类型,因此可以进行转换 指向它遵循通常的规则(并要求一个 reinterpret_cast)。

在很多方面,情况非常像intdouble,其中 void*扮演int(比如说​​)的角色,Fred*扮演double的角色。 static_castint之间double没有问题,但是 int*double*之间的强制转换需要reinterpret_cast

答案 1 :(得分:3)

所有对象指针都可以转换为void*,因此静态强制转换就可以了。但是,在T*U*之间进行转换通常需要重新解释转换,因为任意指针不能相互转换。 (并替换T = Fred*U = void*。)

答案 2 :(得分:3)

static_cast无法将Fred **转换为void **,因为它不是明智的转换:指向Fred*void*的指针不一定以相同的方式创建(即某些平台上的对齐问题)。您可以确定可以指向内存中任何字节的void*也可以指向Fred对象,但void**指针的情况并非如此。

答案 3 :(得分:1)

声明

以下是挥手,目的是让事情易于理解,而不是技术上正确的描述。

挥手

引入void的一种可能方式是:

void与<{{1>}通用超类类似(不一样)。

Object可以看作是每个类和非类类型的抽象基础。 (有了这个比喻,void也将是一个准虚拟基类型:转换为void永远不会模棱两可。)

因此,您可以看到从void*T*的隐式转换作为派生到基础的转换,反向void*就像是派生转发的基础。当static_cast没有真正指向void*时,您不应该执行T(当static_cast<T*>没有真正指向Base*时,您不应该做Derived)。

免责声明,

严重的是, static_cast<Derived*> 是抽象基类,在许多情况下无法正式视为一个基类:

  • 当使用多重继承时,您无法正式将void描述为虚拟基础(或void将中断)或非虚拟基础(或转换为static_cast将不明确)。
  • 没有void*类型。这个基类 metaphor 只是扩展到了指针之外。

请不要告诉别人“void&是通用的C ++基类,就像Java Object”。 如果没有完整的免责声明,请不要重复我在这里写的任何内容。

仅在某些情况下, void的行为类似于基类,用于指针隐式转换和强制转换。

你不能写基于隐喻的程序,而是基于真正的C ++规则。

这个比喻可能有所帮助。或不。无论哪种方式,都不会试图根据隐喻得出逻辑结论。