C ++ Objekt, Mitglied Memory Position Offset
Frage
Gibt es eine bessere Methode, um die Positions zu schaffen Offset eines Datenelements des Objekts als das folgende?
class object
{
int a;
char b;
int c;
};
object * o = new object();
int offset = (unsigned char *)&(object->c) - (unsigned char *)o;
delete o;
Lösung
In diesem Fall Ihre Klasse ist POD, so können Sie das offsetof
Makro aus <cstddef>
verwenden.
In der Praxis in den meisten Implementierungen für die meisten Klassen können Sie den gleichen Trick verwenden, die offsetof typischerweise verwendet:
int offset = &(((object *)0)->c) - (object *)0;
Keine Notwendigkeit, tatsächlich ein Objekt erstellen, obwohl Sie einige Compiler-Warnungen abwehren müssen, weil dies nicht zur Arbeit gewährleistet ist.
Beachten Sie auch, dass, wenn Ihre Klasse hat jede Mehrfachvererbung, dann für (mindestens) alle bis auf eine Basis, (void*)(base*)some_object != (void*)(derived*)some_object
. Also muss man vorsichtig sein, was Sie das zu kompensieren gilt. Solange Sie es auf einen Zeiger auf die Klasse relativ zu berechnen und anzuwenden, die das Feld tatsächlich definiert (das heißt, nicht versuchen, den Offset einer Basisklasse Feld von einer abgeleiteten Klasse Zeiger zu arbeiten) Sie fast sicher werde sein fein. Es gibt keine Garantien über das Objekt Layout, aber die meisten Implementierungen machen es die offensichtliche Art und Weise.
Technisch für jede nicht-POD-Klasse, macht es keinen Sinn, über „den Offset“ ein Feld von dem Basiszeiger zu sprechen. Der Unterschied zwischen den Zeigern ist nicht das gleiche für alle Objekte dieser Klasse sein, erforderlich ist.
Andere Tipps
Es gibt keine Notwendigkeit, tatsächlich ein Objekt zu erstellen:
(size_t)&(((object*)0)->c)
Das heißt, die Adresse eines Elements in einem Objekt bei der Adresse Null das dieses Elements in das Objekt versetzt ist.
Natürlich haben Sie Zugriff auf das Element benötigen, so können Sie entweder brauchen sie eine struct
machen oder einen public:
Zugriffsmodifikator hinzuzufügen.
Dies ist, wie offsetof
implementiert ist, zumindest für die meisten Compiler.
Anstatt einen Zeiger.
Sie können einen Zeiger auf ein Element verwenden.
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;
}
zu Martins Antwort hinzuzufügen, wie in "Design und Entwicklung von C ++", erklärte von Stroustrup (Abschnitt [13.11]):
Zeiger auf Datenelemente haben sich als nützliche Art und Weise das Layout zum Ausdruck von eine C ++ Klasse in einer Implementierung [Hübel 1992]
Sandeep war so freundlich wie das ursprüngliche Papier zu konvertieren und zur Verfügung stellt auf http://sandeep.files.wordpress.com/2008/07/ps.pdf
Beachten Sie, dass die Umsetzung vordatierte C beschrieben ++ RTTI, aber ich gelegentlich noch den Zeiger-to-Mitglied Zeug.