オブジェクトのデータメンバーの位置オフセットを確立するためのより良い方法は、次の方法よりも優れていますか?
class object
{
int a;
char b;
int c;
};
object * o = new object();
int offset = (unsigned char *)&(object->c) - (unsigned char *)o;
delete o;
offsetof
この場合、クラスはPODであるため、からマクロを使用できます<cstddef>
。
実際には、ほとんどの実装では、ほとんどのクラスで、offsetofが通常使用するのと同じトリックを使用できます。
int offset = &(((object *)0)->c) - (object *)0;
実際にオブジェクトを作成する必要はありませんが、これが機能することが保証されていないため、コンパイラの警告と戦う必要がある場合があります。
クラスに多重継承がある場合は、(少なくとも)1つのベースを除くすべてのベースについても注意してください(void*)(base*)some_object != (void*)(derived*)some_object
。したがって、オフセットを適用する対象に注意する必要があります。フィールドを実際に定義するクラスへのポインターを基準にして計算して適用する限り(つまり、派生クラスポインターからの基本クラスフィールドのオフセットを計算しようとしないでください)、ほぼ確実に大丈夫。オブジェクトのレイアウトについての保証はありませんが、ほとんどの実装はそれを明白な方法で行います。
技術的には、POD以外のクラスの場合、ベースポインタからのフィールドの「オフセット」について話すことは意味がありません。ポインタ間の違いは、そのクラスのすべてのオブジェクトで同じである必要はありません。
実際にオブジェクトを作成する必要はありません。
(size_t)&(((object*)0)->c)
つまり、アドレス0にあるオブジェクトのメンバーのアドレスは、オブジェクトへのそのメンバーのオフセットです。
もちろん、メンバーへのアクセスが必要になるため、メンバーにするか、アクセス修飾子struct
を追加する必要があります。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;
}
Stroustrupによる「C++の設計と進化」(セクション[13.11])で述べられているように、Martinsの回答に追加するには:
データメンバーへのポインタは、実装でC ++クラスのレイアウトを表現するための便利な方法であることが証明されています[Hübel、1992]。
Sandeepは、元の紙を変換してhttp://sandeep.files.wordpress.com/2008/07/ps.pdfで利用できるようにしてくれました。
実装では以前のC++RTTIについて説明しましたが、メンバーへのポインターを使用することもあります。