12

我有一个指向 a 的指针的 const 指针,但Fred我不明白为什么 astatic_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将指针转换为指针就Fred可以了void

4

4 回答 4

12

不要求 aFred*和 avoid*具有相同的大小和表示。(我曾在他们没有的机器上工作过,尽管那是在我的 C++ 时代之前。)当你转换Fred*为 时 void*,你会得到一个新的指针,它可能具有不同的大小和表示形式,但没有关于大小和表示的信息void*指向的对象的表示。你知道它是未知的,使用它的唯一方法void*是将它转换回 Fred*(模数,如 cv-qualifiers)。当您转换Fred** 为 时void**,您正在从指向具体类型的指针(指向 a 的指针Fred*)转换为指向另一个具体类型的指针(指向 a 的指针)void*)。而且由于不能保证这两种具体类型具有相同的大小和表示形式,因此转换需要一个 reinterpret_cast. void是一种特殊的非具体类型,因此您可以 static_cast将指向任何类型的指针与指向void. void*只是另一种具体的指针类型,因此在指向它的指针之间进行转换遵循通常的规则(并且需要 a reinterpret_cast)。

在很多方面,情况很像intand double, where void*扮演int(say)的角色,扮演 的Fred*角色double。在andstatic_cast之间没有问题,但是在和require之间进行强制转换。intdoubleint*double*reinterpret_cast

于 2012-07-10T10:12:10.900 回答
3

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

于 2012-07-10T10:06:34.667 回答
3

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

于 2012-07-10T10:08:50.523 回答
1

免责声明

以下是为了使事情易于理解而挥手致意,而不是技术上正确的描述。

挥手的

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

void与Java通用超类相似(不一样) 。Object

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

因此,您可以将隐式转换从T*tovoid*视为派生到基的转换,而反过来static_cast就像派生向下转换的基。当 avoid*没有真正指向 aT时,你不应该做 a static_cast<T*>(当 aBase*没有真正指向 aDerived时,你不应该做 a static_cast<Derived*>)。

免责声明,再次

严重的是, void不是一个抽象基类,并且在许多情况下不能被正式视为一个:

  • 您不能正式将其描述void为虚拟基(或static_cast会中断)或非虚拟基(或void*在使用多重继承时转换为模棱两可)。
  • 没有void&类型。这个基类隐喻确实超出了指针。

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

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

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

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

于 2012-07-24T06:11:30.630 回答