Pregunta

¿Hay un mejor método para establecer el desplazamiento del miembro de datos de un objeto de la siguiente posicional?

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

object * o = new object();
int offset = (unsigned char *)&(object->c) - (unsigned char *)o;
delete o;
¿Fue útil?

Solución

En este caso, su clase es POD, por lo que puede utilizar la macro offsetof de <cstddef>.

En la práctica, en la mayoría de las implementaciones, para la mayoría de las clases, puede utilizar el mismo truco, que normalmente utiliza offsetof:

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

No hay necesidad de crear realmente un objeto, aunque puede que tenga que luchar contra algunas advertencias del compilador, porque esto no se garantiza que funcione.

Tenga cuidado también de que si su clase tiene herencia múltiple, a continuación, para (al menos) todas menos una base, (void*)(base*)some_object != (void*)(derived*)some_object. Así que hay que tener cuidado con lo que aplicar la diferencia a. Mientras se calcula y aplica en relación con un puntero a la clase que realmente define el campo (es decir, no se trata de trabajar a cabo el desplazamiento de un campo de clase base de un puntero de clase derivada) es casi seguro que será multa. No hay garantías sobre la disposición objeto, pero la mayoría de las implementaciones de hacerlo de la manera obvia.

Técnicamente para cualquier clase no POD, no tiene sentido hablar de "el desplazamiento" de un campo de la base de puntero. La diferencia entre los punteros no está obligado a ser el mismo para todos los objetos de esa clase.

Otros consejos

No hay necesidad de crear realmente un objeto:

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

Es decir, la dirección de un miembro en un objeto en la dirección de cero es el desplazamiento de dicho miembro en el objeto.

Por supuesto, tendrá acceso al miembro, por lo que necesita, ya sea que sea un struct o añadir un modificador de acceso public:.

Esto es cómo se implementa offsetof, al menos para la mayoría de los compiladores.

En lugar de un puntero.
Se puede utilizar un puntero a un miembro.

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

Para añadir a la respuesta Martins, como se indica en "Diseño y Evolución de C ++" por BS (sección [13,11]):

  

punteros a miembros de datos han demostrado una   manera útil de expresar la disposición de   una clase de C ++ en una implementación   [Hübel, 1992]

Sandeep ha sido tan amable de convertir el documento original y que esté disponible en http://sandeep.files.wordpress.com/2008/07/ps.pdf

Tenga en cuenta que la aplicación se describe depredado C ++ RTTI, pero de vez en cuando todavía utilizan la materia-puntero a miembro.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top