Как получить доступ к переменным-членам класса, используя пустой указатель, но не объект

Я пытаюсь получить доступ к переменным-членам класса без использования объекта. пожалуйста, дайте мне знать, как идти.

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;
}
 Chris Lutz10 июл. 2009 г., 08:19
Этот вопрос касается классов, и это определенно не C, а твердо C ++.

Ответы на вопрос(6)

Просто не может быть ситуации, когда можно оправдать такой доступ. Просто должно быть другое решение.

 12 мар. 2012 г., 22:39
Я полностью не согласен. Динамическое получение переменной-члена было бы чрезвычайно полезным. Если бы я мог передать переменную-член, которую я хочу получить доступ к функции, это помогло бы при программировании более высокого порядка. Как бы то ни было, мне нужно создать оболочку функции и использовать указатель на функцию.

dirty:

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

Длинный ответ: можно, но это сильно зависит от реализации. Если вы сбросите память, найденную в * p, вы увидите где-то там, что вы ищете - a и b. Но вы, скорее всего, увидите и другие вещи. Что это такое, что это значит, насколько оно велико (и, как следствие, где фактически живут a и b), зависит от реализации.

предоставленный Джоном Кугельманом, поскольку у нового участника не было достаточной репутации, поэтому я опубликовал его как ответ.

offsetof - это функция C, используемая со структурами, где каждый член является публичным, не уверенным, можем ли мы ссылаться на частные переменные, как указано в ответе.

Однако этого можно добиться, заменив offsetof простым sizeof, конечно, когда мы уверены в типе элементов данных.

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

Насколько мне известно, вы не сможете получить доступ. К тому времени, когда вы присвоили p, он не ссылается на o1 здесь и p не может заменить pMem в (o1. * pMem) (), так как p не определен как член функции для TestMem.

Решение Вопроса

offsetof() макрос из<stddef.h>, к несчастьюoffsetof() имеет некоторые довольнодраконовские ограничения в C ++:

Because of the extended functionality of structs in C++, in this language, the use of offsetof is restricted to "POD [plain old data] types", which for classes, more or less corresponds to the C concept of struct (although non-derived classes with only public non-virtual member functions and with no constructor and/or destructor would also qualify as POD).

Так что если вы делаетеa а такжеb общественности и избавиться отTestMemконструктор, вы можете написать что-то вроде этого для доступаa:

C++ style:
#include <cstddef>

int vala = *reinterpret_cast<int *>(reinterpret_cast<char *>(&o1)
           + offsetof(TestMem, a));
C style:
#include <stddef.h>

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

Обратите внимание, что вам нужно использовать&o1 здесь неp, который является указателем на функцию. АдресTestMem::TestMem1 не будет иметь никакого отношения к местоположениюa а такжеb, Методы класса не находятся в памяти где-либо рядом с переменными-членами класса.

"Неправильно" способ просто угадать, гдеa а такжеb в памяти. Скорее всего, они имеют смещения 0 и 4 от началаo1соответственно. Так что этот код будет работать большую часть времени:

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

Здесь много предположений. Это предполагает, что целые числа составляют 4 байта и что между заполнением нетa а такжеb, С другой стороны, он не имеет каких-либо ограничений сверху:a а такжеb не нужно быть публичным, у вас может быть конструктор, что угодно.

указатели относительно объекта. Они определяются по префиксу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, ...).

Ваш ответ на вопрос