我有一个指针指向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
的指针。
答案 0 :(得分:12)
不要求Fred*
和void*
具有相同的尺寸
和代表。 (我曾在他们没有的机器上工作,
虽然那是在我的C ++日之前。)当你将Fred*
转换为
void*
,你得到一个新的指针,可能有不同的大小和
表示,但没有关于大小和信息的信息
void*
指向的对象的表示。你知道它是
未知,使用此void*
的唯一方法是将其强制转换为
Fred*
(模块化的事物,如cv-qualifiers)。转换Fred**
时
到void**
,你将指针转换为具体类型(a
指向Fred*
的指针指向另一个具体类型的指针(指针
到void*
)。而且由于不能保证这两个具体
类型具有相同的大小和表示,转换需要a
reinterpret_cast
。 void
是一种特殊的,非具体的类型,所以你可以
static_cast
指向void
指针的任何类型的指针。
void*
只是另一种具体的指针类型,因此可以进行转换
指向它遵循通常的规则(并要求一个
reinterpret_cast
)。
在很多方面,情况非常像int
和double
,其中
void*
扮演int
(比如说)的角色,Fred*
扮演double
的角色。
static_cast
和int
之间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 ++规则。
这个比喻可能有所帮助。或不。无论哪种方式,都不会试图根据隐喻得出逻辑结论。