我试图在不使用对象的情况下访问类的成员变量。请让我知道如何去做。
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;
}
答案 0 :(得分:5)
执行此操作的“正确”方法是使用<stddef.h>
中的offsetof()
宏。不幸的是,offsetof()
在C ++中有一些draconian restrictions:
由于C ++中结构体的扩展功能,在这种语言中,
offsetof
的使用仅限于“POD [普通旧数据]类型”,对于类,或多或少对应于C概念结构(尽管只有公共非虚拟成员函数且没有构造函数和/或析构函数的非派生类也可以作为POD)。
因此,如果您将a
和b
公开并摆脱TestMem
的构造函数,您可以编写类似这样的内容来访问a
:
#include <cstddef>
int vala = *reinterpret_cast<int *>(reinterpret_cast<char *>(&o1)
+ offsetof(TestMem, a));
#include <stddef.h>
int vala = *(int *) ((char *) &o1 + offsetof(TestMem, a));
请注意,您需要在此使用&o1
,而不是p
,这是一个函数指针。 TestMem::TestMem1
的地址与a
和b
的位置无关。类方法不驻留在类成员变量附近的任何内存中。
“错误”的方法是猜测a
和b
在内存中的位置。最有可能的是,它们分别位于o1
开头的偏移0和4处。所以这段代码大部分时间都可以工作:
int vala = *(int *) ((char *) &o1 + 0);
int valb = *(int *) ((char *) &o1 + 4);
这里有很多假设。这假设int是4个字节,并且a
和b
之间没有填充。另一方面,它没有上述任何限制:a
和b
不需要公开,你可以有一个构造函数,无论如何。
答案 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, ...)
。