1

给定一个类实例和一个指向字段的指针,我们可以获得指向该类实例的字段变量的常规指针——如以下代码中的最后一个赋值;

class A
{
public:
    int i, j;
};
int main(){
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;
}

是否可以反转这种转换:给定类实例A a;int* r获取int A::* p(如果给定的指针不在给定的实例中,则为 NULL ptr),如代码所示:

class A
{
public:
    int i, j;
};
int main(){
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;
    int A::*s = // a--->r -how to extract r back to member pointer?
}

我能想到的唯一方法是编写一个函数,该函数采用 A 的每个已知字段,计算给定实例的地址并与给定地址进行比较。然而,这需要为每个类编写自定义代码,并且可能难以管理。它也有次优的性能。

我可以想象这种转换可以由编译器在我知道的所有实现下的几个操作中完成——这样的指针通常只是结构中的一个偏移量,所以它只是一个减法和范围检查,看看给定的指针是否真的在这个类存储中. 虚拟基类增加了一些复杂性,但我认为没有什么编译器无法处理。然而,似乎因为标准不需要它(是吗?)没有编译器供应商关心。

还是我错了,这种转换存在一些根本问题?

编辑:

我看到对我要问的内容有一点误解。简而言之,我要问是否:

  • 它已经有一些实现(我的意思是在编译器级别),但由于几乎没有人使用它,几乎没有人知道它。
  • 标准中没有提到它,也没有编译器供应商提到它,但原则上它是可以实现的(再次:由编译器,而不是编译代码。)
  • 这种操作存在一些深层次的问题,我错过了。

我的问题是——哪一个是真的?如果是最后一个 - 潜在的问题是什么?

我不是在寻求解决方法。

4

2 回答 2

0

AFAIK C++ 不提供完全反射,您需要这样做。

一种解决方案是自己提供反射(您描述的方式是一种方式,它可能不是最好的方式,但它会起作用)。

一个完全不可移植的解决方案是找到可执行文件并使用它可能包含的任何调试信息。显然不可移植,并且需要调试信息开始。

在http://www.garret.ru/cppreflection/docs/reflect.html的介绍部分对反射问题和不同的可能方法有一个不错的描述

编辑:

正如我上面所写,没有可移植和通用的解决方案。但是可能有一种非常不可移植的方法。我不会在这里给你一个实现,因为我目前没有 C++ 编译器来测试它,但我会描述这个想法。

基础是 Dave 在他的回答中所做的:利用指向成员的指针通常只是一个偏移量这一事实。问题在于基类(尤其是虚拟和多重继承)。您可以使用模板来处理它。您可以使用动态转换来获取指向基类的指针。并最终将该指针与原始指针进行比较,以找出基址的偏移量。

于 2012-09-17T20:34:21.360 回答
0

没有跨平台方法可以做到这一点。指向成员值的指针通常实现为指向对象开始的偏移量。利用这个事实,我做了这个(在 VS 中工作,没有尝试过其他任何东西):

class A
{
public:
    int i, j;
};

int main()
{
    A a;
    int A::*p = &A::i;
    int* r = &(a.*p); // r now points to a.i;

    union
    {
        std::ptrdiff_t offset;
        int A::*s;
    };

    offset = r - reinterpret_cast<int*>(&a);
    a.*s = 7;
    std::cout << a.i << '\n';
}
于 2012-09-17T20:36:22.637 回答