有没有比以下更好的方法来建立对象数据成员的位置偏移?
class object
{
int a;
char b;
int c;
};
object * o = new object();
int offset = (unsigned char *)&(object->c) - (unsigned char *)o;
delete o;
在这种情况下,您的类是 POD,因此您可以使用offsetof
来自<cstddef>
.
实际上,在大多数实现中,对于大多数类,您可以使用 offsetof 通常使用的相同技巧:
int offset = &(((object *)0)->c) - (object *)0;
无需实际创建对象,尽管您可能不得不抵制一些编译器警告,因为这不能保证有效。
还要注意,如果您的类有任何多重继承,那么(至少)除了一个基类之外的所有类,(void*)(base*)some_object != (void*)(derived*)some_object
. 所以你必须小心你应用偏移量。只要您计算并相对于指向实际定义该字段的类的指针应用它(也就是说,不要试图从派生类指针中计算出基类字段的偏移量),您几乎肯定会美好的。没有关于对象布局的保证,但大多数实现都以明显的方式做到这一点。
从技术上讲,对于任何非 POD 类,谈论字段与基指针的“偏移量”是没有意义的。对于该类的所有对象,指针之间的差异不需要相同。
无需实际创建对象:
(size_t)&(((object*)0)->c)
也就是说,对象中地址为零的成员的地址是该成员在对象中的偏移量。
当然,您需要访问该成员,因此您需要将其设为 astruct
或添加public:
访问修饰符。
这就是offsetof
实现的方式,至少对于大多数编译器而言。
而不是指针。
您可以使用指向成员的指针。
class X;
typedef int X::* PtrToMemberInt; // Declare a pointer to member.
class X
{
int a;
char b;
float c;
public:
static PtrToMemberInt getAPtr()
{
return &X::a;
}
int d;
};
int main()
{
// For private members you need to use a public method to get the address.
PtrToMemberInt aPtr = X::getAPtr();
// For public members you can take the address directly;
PtrToMemberInt dPtr = &X::d;
// Use the pointer like this:
X a;
a.*aPtr = 5;
a.*dPtr = 6;
}
为了补充 Martins 的答案,如 Stroustrup 的“C++ 的设计和演变”(第 [13.11] 节)所述:
指向数据成员的指针已被证明是一种在实现中表达 C++ 类布局的有用方法 [Hübel, 1992]
Sandeep 非常友好地转换了原始论文并在http://sandeep.files.wordpress.com/2008/07/ps.pdf上提供
请注意,实现描述早于 C++ RTTI,但我偶尔仍然使用指向成员的东西。