为什么我必须 reinterpret_cast 指针指针?

Why do I Have to reinterpret_cast Pointer Pointers?

所以这个static_cast代码是完全合法的:

int n = 13;
void* pn = static_cast<void*>(&n);
void** ppn = &pn;

然而这必须做成reinterpret_cast才能编译:

int n = 13;
int* foo = &n;
void** bar = static_cast<void**>(&foo);

如果我不更改它,我会收到错误消息:

error C2440: static_cast: cannot convert from int ** to void ** note: Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast

所以我认为问题是 "the types are unrelated"。但是我仍然不明白,如果从 int*void* 没关系,它们怎么可能与 int**void** 无关?

intvoid 没有任何关系。 int**void** 也是如此,因此它们无法使用 static_cast.

进行转换

void*然而,是特别。任何数据指针类型(包括 int*)都可以 static_cast 转换为 void* 并返回,尽管没有类型与 void 相关(更进一步,转换为 void* 不需要强制转换,因为它是隐式的)。 int* 没有这个 属性,void** 也没有,除了 void*.

也没有任何其他指针

授予 void* 的额外自由带有额外的限制。 void* 不能间接使用,也不能与指针运算一起使用。这些限制是唯一可能的,因为永远不会有 void 类型的对象。或者从相反的角度来看,由于这些限制,void 的对象无法存在。

void** 不能给予这些自由,因为它不能给予同样的限制。它不能被赋予这些限制,因为 void* 对象确实存在并且它们需要存在。如果我们不能间接或迭代 void**,那么我们就不能使用 void* 的数组。

void* pn = static_cast<void*>(&n);

是隐式转换;你也可以写

void *pn = &n;

表示pn存储了一个指向某个对象类型的指针;程序员有责任知道该对象类型是什么。要回退,您需要 static_cast:

int *pi = static_cast<int*>(pn);

请注意,使用 static_cast 转换为与原始类型有显着差异的任何类型(float 有显着差异,const int 则没有)是一种重新解释的方式。您应该拼写 reinterpret_cast 而不是隐式转换(或 static_cast),然后是 static_cast

这就是 void* 的全部目的,一个可以追溯到 C 的概念,其中强制转换显然是 C 风格的强制转换(不是 static_cast...),但在其他方面具有相同的含义.

回到C和C++中声明的语法:

指向int的指针的声明是int (*pi);(括号没用但有助于说明这一点),你可以这样读:我声明表达式(*pi)有类型int。您可以这样阅读函数声明:在 int f(int i); 中,我声明如果 i 具有类型 int,则 f(i) 具有类型 int.

声明 void (*pi); 看起来像一个指向 void 的指针,但不存在 void 类型的对象,表达式 *pi 不是即使格式正确,也没有意义。这是类型系统中的 特例 :语法表示 "pointer to void",语义表示 "pointer to something".

在 C 和 C++ 中,指针对象是第一个 class 对象,您可以获取它的地址并拥有指向指针的指针等。(与 Java 相比,其他引用基本类型不是 class 对象。)

所以你可以有一个int**, int***... pointers to (pointers ... to int);出于同样的原因,您可以拥有 void**:声明为指向(指向 void 的指针)的指针,在语义上是指向(指向某物的指针)的指针。

就像指向 int 的指针不能被赋值给指向 float 的指针一样:

float *f = &i; // ill-formed

由于类型不匹配,无法将不同于 void** 的类型分配给 void**取消引用 void** 的结果必须是一个 void* 对象.