将指向数据成员的指针转换为void *

Convert pointer to data member to void *

本文关键字:转换 void 指针 数据成员      更新时间:2023-10-16

我知道我可以获得指向类或结构的数据成员的指针,但下面代码的最后一行无法编译:

struct abc
{
    int a;
    int b;
    char c;
};
int main()
{
    char abc::*ptt1 = &abc::c;
    void *another_ptr = (void*)ptt1;
}

为什么我不能将ptt1转换为另一个ptr?我们讨论的是指针,所以一个指针应该与另一个指针具有相似的维度(尽管概念上不同)?

指向非静态类成员类型的指针与指向对象类型指针不同;它们的行为非常不同。事实上,你甚至不能用*解引用指向成员的指针。要通过指向成员的指针访问成员,可以使用.*->*操作符。如果您可以将其强制转换为像这样的对象指针类型,那么,如果您使用*对其解引用,将会发生什么?

只有对象指针类型有到void*(§4.10)的标准转换:

右值类型为"指向cv T",其中T是对象类型,可以转换为类型为"指向cv void"的右值。

它们是如此不同,以至于标准甚至特意确保术语"指针"不包括指向非静态成员的指针(第3.9.2节):

除了指向静态成员的指针外,指向"指针"的文本不适用于指向成员的指针。

主要原因是没有要求指针的大小和表示形式与指向数据的指针。在实践中,很难想象一个指针不能放入void*的数据成员,因为指向数据成员的指针实际上只需要包含一个偏移量。粗略地说,指向数据成员的指针将永远不需要大于size_t,而void*必须大于至少和size_t一样大。另一方面,它也有可能轻松包含指针中不合法的位模式。事实上,正如Steve Jessop所指出的,指向成员的指针确实需要额外的信息,因为如果成员位于虚基中,则其偏移量取决于最派生的类,并且必须根据指针中的额外信息动态计算。

一般来说,void*只能包含指向数据的指针。它必须和最大的数据指针一样大(char*),但是指向函数的指针和成员指针可以更大,而不是适合(和指针指向成员函数几乎没有合适的)。

你想做这样的事情吗?

struct ABC
{
    int a;
    int b;
    char c;
};
int main()
{
    ABC abc;
    char *ptt1 = &abc.c;
    void *another_ptr = (void*)ptt1;
}