如何使用void指针但不是Object来获取对类的成员变量的访问权限

时间:2009-07-10 04:19:23

标签: c++ pointers

我试图在不使用对象的情况下访问类的成员变量。请让我知道如何去做。

class TestMem
{
    int a;
    int b;
public:
    TestMem(){}
    void TestMem1()
    {
        a = 10;
        b = 20;
    }
};

void (TestMem::*pMem)();

int main(int argc, char* argv[])
{

    TestMem o1;
    pMem = &(TestMem::TestMem1);

    void *p = (void*)&pMem;
    // How to access a & b member variables using variable p
    getch();
    return 0;
}

6 个答案:

答案 0 :(得分:5)

执行此操作的“正确”方法是使用<stddef.h>中的offsetof()宏。不幸的是,offsetof()在C ++中有一些draconian restrictions

  

由于C ++中结构体的扩展功能,在这种语言中,offsetof的使用仅限于“POD [普通旧数据]类型”,对于类,或多或少对应于C概念结构(尽管只有公共非虚拟成员函数且没有构造函数和/或析构函数的非派生类也可以作为POD)。

因此,如果您将ab公开并摆脱TestMem的构造函数,您可以编写类似这样的内容来访问a

C ++风格:

#include <cstddef>

int vala = *reinterpret_cast<int *>(reinterpret_cast<char *>(&o1)
           + offsetof(TestMem, a));

C风格:

#include <stddef.h>

int vala = *(int *) ((char *) &o1 + offsetof(TestMem, a));

请注意,您需要在此使用&o1,而不是p,这是一个函数指针。 TestMem::TestMem1的地址与ab的位置无关。类方法不驻留在类成员变量附近的任何内存中。


“错误”的方法是猜测ab在内存中的位置。最有可能的是,它们分别位于o1开头的偏移0和4处。所以这段代码大部分时间都可以工作:

int vala = *(int *) ((char *) &o1 + 0);
int valb = *(int *) ((char *) &o1 + 4);

这里有很多假设。这假设int是4个字节,并且ab之间没有填充。另一方面,它没有上述任何限制:ab不需要公开,你可以有一个构造函数,无论如何。

答案 1 :(得分:3)

简单回答:不要这样做。

没有任何情况可以证明你这样做是合理的。必须有一个不同的解决方案。

答案 2 :(得分:1)

我想出了一个解决方案但它

class TestMem
{
public:
    int a;
    int b;
    TestMem(){}
    void TestMem1()
    {
        a = 10;
        b = 20;
    }
};

void* offset(void* ptr, ...)
{
  va_list ap;
  va_start(ap, ptr); // get 1st argument's address

  long i = va_arg(ap, long); // get next argument
  va_end(ap);

  return (char*)ptr + i;
}

void test()
{
  TestMem t;
  void* p = (TestMem*)&t;
  t.a = 8;
  t.b = 9;
  printf("%i\n", *(int*)offset(p, &TestMem::a));
  printf("%i\n", *(int*)offset(p, &TestMem::b));
}

答案 3 :(得分:1)

我想对John Kugelman提供的答案发表评论,作为一名新成员并没有足够的声誉,因此将其作为答案发布。

offsetof - 是一个C函数,用于每个成员都是公共的结构,不确定我们是否可以引用答案中提到的私有变量。

然而,当我们确定数据成员的类型时,可以用简单的sizeof替换offsetof来实现同样的目的。

int vala = *reinterpret_cast<int *>(reinterpret_cast<char *>( ptr ) );
int valb = *reinterpret_cast<int *>(reinterpret_cast<char *>( ptr ) + sizeof ( int ) );

据我所知,您将无法访问。 当你指定了p时,它并没有在这里引用o1 p不能替换(o1。* pMem)()中的pMem,因为p未定义为TestMem的函数成员。

答案 4 :(得分:0)

简短的回答:你不能。

答案很长:你可以,但它高度依赖于实现。 如果你转储你在* p找到的内存,你会看到,在那里的某个地方,你正在寻找什么 - a和b。但你很可能也会看到其他一些东西。这些东西是什么,意味着什么,它有多大(以及a和b实际存在的含义)是依赖于实现的。

答案 5 :(得分:0)

总有一种方法。 C ++有成员指针,指向相对于对象的指针。它们的定义是在指针类型上为T::添加前缀*,并使用->*.*成员指针访问运算符来使用它们。所以是的,它看起来很可怕:)。

class T {
    int a, b;
public:
    typedef int T::* T_mem_ptr_to_int;

    static T_mem_ptr_to_int const a_ptr;
    static T_mem_ptr_to_int const b_ptr;
};

T::T_mem_ptr_to_int const T::a_ptr = &T::a;
T::T_mem_ptr_to_int const T::b_ptr = &T::b;

int weird_add(T* left, T* right) {
    return left->*T::a_ptr + right->*T::b_ptr;
}

成员 function 指针的使用频率更高,看起来像Result (T::*ptr_name)(Arg1, Arg2, ...)