【问题标题】:How to gain Access to member variables of a class using void pointer but Not Object如何使用 void 指针而不是对象访问类的成员变量
【发布时间】:2009-07-10 04:19:22
【问题描述】:

我试图在不使用对象的情况下访问类的成员变量。请告诉我该怎么做。

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;
}

【问题讨论】:

  • 这个问题涉及到类,而且肯定不是C,而是C++。

标签: c++ pointers


【解决方案1】:

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

由于C++中structs的扩展功能,在这种语言中,offsetof的使用仅限于“POD [plain old data] types”,对于类来说,或多或少对应了C中struct的概念(尽管仅具有公共非虚拟成员函数且没有构造函数和/或析构函数的非派生类也可以称为 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));

注意这里需要使用&amp;o1,而不是p,它是一个函数指针。 TestMem::TestMem1 的地址与ab 的位置没有任何关系。类方法不会驻留在内存中靠近类成员变量的任何位置。


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

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

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

【讨论】:

    【解决方案2】:

    简单的答案:不要这样做。

    不可能有任何情况可以证明这样的访问是合理的。只是必须有一个不同的解决方案。

    【讨论】:

    • 我完全不同意。动态获取成员变量将非常有用。如果我可以传入我想要访问函数的成员变量,这将有助于高阶编程。实际上,我必须创建一个函数包装器并使用函数指针。
    【解决方案3】:

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

    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));
    }
    

    【讨论】:

      【解决方案4】:

      我想评论 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 的函数成员。

      【讨论】:

        【解决方案5】:

        简短回答:你不能。

        长答案:可以,但它高度依赖于实现。 如果你转储你在 *p 找到的内存,你会在附近的某个地方看到你正在寻找的东西——a 和 b。但是您很可能还会看到其他一些东西。这些东西是什么,它意味着什么,它有多大(以及暗示 a 和 b 实际存在的位置)取决于实现。

        【讨论】:

          【解决方案6】:

          完全有办法。 C++ 有成员指针,即相对于对象的指针。它们是通过在指针类型上为* 加上前缀T:: 来定义的,并通过使用-&gt;*.* 成员指针访问运算符来使用。所以,是的,它看起来很可怕:)。

          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;
          }
          

          这更常用于成员函数指针,看起来像Result (T::*ptr_name)(Arg1, Arg2, ...)

          【讨论】:

            猜你喜欢
            • 2016-05-24
            • 1970-01-01
            • 2016-11-27
            • 1970-01-01
            • 1970-01-01
            • 2021-12-25
            • 1970-01-01
            • 2015-02-04
            • 1970-01-01
            相关资源
            最近更新 更多