Question

Y at-il une meilleure méthode pour établir le décalage de position des données d'un objet de membre que ce qui suit?

class object
{
  int a;
  char b;
  int c;
};

object * o = new object();
int offset = (unsigned char *)&(object->c) - (unsigned char *)o;
delete o;
Était-ce utile?

La solution

Dans ce cas, votre classe est POD, vous pouvez donc utiliser la macro offsetof de <cstddef>.

Dans la pratique, dans la plupart des mises en œuvre, pour la plupart des classes, vous pouvez utiliser la même astuce qui offsetof utilise généralement:

int offset = &(((object *)0)->c) - (object *)0;

Pas besoin de créer réellement un objet, même si vous avez à combattre certains avertissements du compilateur parce que ce n'est pas garanti au travail.

Méfiez-vous aussi que si votre classe a tout l'héritage multiple, puis à (au moins) tout sauf une base, (void*)(base*)some_object != (void*)(derived*)some_object. Donc, il faut faire attention à ce que vous appliquez le décalage. Tant que vous calculez et l'appliquer par rapport à un pointeur vers la classe qui définit en fait le champ (qui est, ne pas essayer de travailler sur le décalage d'un champ de classe de base à partir d'un pointeur de classe dérivée) vous serez certainement bien. Il n'y a aucune garantie sur la mise en page de l'objet, mais la plupart des implémentations font la manière évidente.

Techniquement pour toutes les classes non-POD, il n'a pas de sens de parler de « l'offset » d'un champ du pointeur de base. La différence entre les pointeurs n'est pas nécessaire d'être le même pour tous les objets de cette classe.

Autres conseils

Il n'y a pas besoin de créer réellement un objet:

(size_t)&(((object*)0)->c)

Autrement dit, l'adresse d'un élément dans un objet à l'adresse zéro est le décalage de cet élément dans l'objet.

Bien sûr, vous aurez besoin d'un accès au membre, vous devez soit faire un struct ou ajouter un modificateur d'accès public:.

Voici comment offsetof est mis en œuvre, au moins pour la plupart des compilateurs.

Au lieu d'un pointeur.
Vous pouvez utiliser un pointeur vers un membre.

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;
}

Pour ajouter à réponse Martins, comme indiqué dans "Design et évolution du C ++" par Stroustrup (section [13,11]):

  

pointeurs vers des membres de données ont démontré une   bon moyen d'exprimer la disposition des   une classe C ++ dans une mise en œuvre   [Hübel, 1992]

Sandeep a bien voulu convertir le document original et de le rendre disponible sur http://sandeep.files.wordpress.com/2008/07/ps.pdf

Notez que la mise en œuvre décrit antidatée C ++ RTTI, mais je parfois utiliser encore l'étoffe pointeur à membre.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top