从成员指针获取类/结构对象

时间:2009-06-22 06:24:20

标签: c++

我的C ++结构为

struct myStruct {
    int a;
    int b;
    int c;
}; 

myStruct b;
int *ptr = &b.c;

如何从ptr中恢复myStruct对象?

(我知道我可以使用像C中的container_Of()这样的指针算术来实现这一点。基本上类似

reinterpret_cast<myStruct*>(reinterpret_cast<char *>(ptr) - offsetof(myStruct, c));

我在问是否有任何推荐/优雅的方式?)

5 个答案:

答案 0 :(得分:5)

肯定没有推荐的方法,因为在C ++中完全不推荐这样做。这是正确答案必须是“不要那样做!”的问题之一。

使用C ++而不是C的全部原因是你想要在类中定义数据结构并在其上定义合理的操作,而不是让整个程序知道数据结构的内部布局。

也就是说,您描述的offsetof技术将适用于普通的旧数据对象,因为它们与C结构没有区别。

答案 1 :(得分:3)

因为 ptr 不知道它的重叠结构,所以我认为没有一种优雅的方法可以回到 myStruct 。 我只是建议不要这样做!

答案 2 :(得分:1)

您的reinterpret_cast解决方案是达到您想要的标准方式。它必须涉及至少一个演员表的原因是你想要执行的操作本质上是不安全的。显然,并非每个指向int的指针都是指向myStruct的第三个成员的指针,因此无法使用简单的类型安全方式来执行转换。

答案 3 :(得分:1)

你的文字&amp;示例使用POD结构;但是,你的标题也会讨论类。以下答案不适用于非POD类型。

对于POD类型,请查看"offsetof" macro ....

找到偏移量,使用&amp;用于备份的指针算术说一个char *基数。

答案 4 :(得分:0)

你可以使用这样的事实:当你从指向基类的指针进行转换时,这不是唯一的基类,编译器会调整指针,使它指向超类的开头。因此,如果你的“c”成员存在于某个基类的开头,你可以这样做:

struct myStructBase1 { int a; };
struct myStructBase2 { int b; };
struct myStructBase3 { int c; };

struct myStruct : public myStructBase1,myStructBase2,myStructBase3 {
    int d;
};

int main() {
    myStruct my;

    int * bptr = &my.b;
    int * cptr = &my.c;
    // The only dirty part in the code...
    myStructBase2 * base2ptr = reinterpret_cast<myStructBase2*> (bptr);
    myStructBase3 * base3ptr = reinterpret_cast<myStructBase3*> (cptr);

    // In each (myStruct*) cast the pointers are adjusted to point to the super class.
    cout << &my << endl <<
            (myStruct*) base2ptr << endl <<
            (myStruct*) base3ptr << endl;
    return 0;
}
// Output:
// 0xbfbc779c
// 0xbfbc779c
// 0xbfbc779c

对此工作的要求是:如果成员是其类中的第一个成员,那么它在对象中的地址等于该对象的地址(该类的对象)。我我不确定这是不是真的。

编辑:当包装基类为POD时,它应该成立。经过以下修改后:

struct myStructBase1 { int a; virtual void g() {} };
struct myStructBase2 { int b; virtual void f() {} };
struct myStructBase3 { int c;  };
struct myStruct : public myStructBase1,myStructBase2,myStructBase3 {
    int d;
    virtual void h() {}
};

输出结果为:

0xbfa305f4
0xbfa305f8
0xbfa305f4

对于c成员,约束仍然成立。所以一般来说答案是:是的,还有另一种方法。但是,为每个“可逆”成员定义基类可能不是明智的方式..