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;
War es hilfreich?

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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top