因此,此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);
如果我不更改它,则会收到错误消息:
错误C2440:
static_cast
:无法从int **
转换为void **
注意:指向的类型无关。转换需要reinterpret_cast
,C样式强制转换或函数样式强制转换
所以我认为问题是“类型无关”。但是,我仍然不明白,如果从int*
到void*
可以吗,它们如何与int**
和void**
无关?
答案 0 :(得分:7)
int
与void
毫无关系。 int**
和void**
也是一样,因此无法使用static_cast
进行转换。
void*
是特殊。尽管没有与int*
相关的类型,任何数据指针类型(包括static_cast
)都可以void*
到void
并返回{{1} }不需要强制转换,因为它是隐式的)。 void*
没有此属性,int*
也没有void**
之外的任何其他指针。
已授予void*
的其他自由带有附加的限制。 void*
不能被间接使用,也不能与指针算法一起使用。这些限制是唯一可能的,因为永远不会有void*
类型的对象。或者从相反的角度来看,由于这些限制,void
的对象不存在。
void
这些自由,因为不能给予相同的限制。不能赋予这些限制,因为void**
对象确实存在并且需要存在。如果我们不能间接或迭代void*
,那么就不能使用void**
数组。
答案 1 :(得分:0)
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
...),但在其他方面具有相同的含义。 / p>
回到C和C ++中的声明语法:
指向int
的指针的声明为int (*pi);
(括号没有用,但有助于说明这一点),您可以这样阅读:我声明表达式(*pi)
的类型为{{ 1}}。您可以这样阅读函数声明:在int
中,我声明如果int f(int i);
的类型为i
,则int
的类型为f(i)
。
声明int
看起来像是指向void (*pi);
的指针,但没有类型为void
的对象,表达式void
也不是很好形成,这没有任何意义。在类型系统中,这是特殊情况:语法为“指向无效指针”,语义为“指向某物的指针”。
在C和C ++中,指针对象是第一类对象,您可以获取其地址并具有指向指针的指针等。(与Java相比,在Java中,像其他基本类型这样的引用不是类对象)。 / p>
因此,您可以拥有*pi
,int**
...的指针(指向int***
的指针);出于相同的原因,您可以使用int
:像指针一样指向(指向void的指针),从语义上来说,指向指针(指向某物的指针)。
就像没有转换的情况一样,指向void**
的指针不能分配给指向int
的指针:
float
由于类型不匹配,无法将与float *f = &i; // ill-formed
不同的类型分配给void**
:取消引用void**
的结果必须为{{1 }}对象。