是否可以将常规指针转换为指向类字段的指针

时间:2012-09-17 20:13:54

标签: c++ pointers type-conversion field

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

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的每个已知字段,计算给定实例的地址并与给定的地址进行比较。然而,这需要为每个类编写自定义代码,并且可能难以管理。它的表现也不是很理想。

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

或者我错了,这种转换存在一些基本问题?

修改

我看到对我所询问的内容存在一些误解。总之,我问的是:

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

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

我不是要求解决方法。

2 个答案:

答案 0 :(得分:0)

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

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

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

http://www.garret.ru/cppreflection/docs/reflect.html

的引言部分对反思问题及其可能的不同方法进行了不错的描述

编辑:

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

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

答案 1 :(得分: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';
}