2009-01-08 10 views
41

Si tengo una clase de la siguiente maneraEstructura de un objeto de C++ en la memoria Vs un Struct

class Example_Class 
    { 
     private: 
     int x; 
     int y; 
     public: 
     Example_Class() 
     { 
      x = 8; 
      y = 9; 
     } 
     ~Example_Class() 
     { } 
    }; 

y una estructura de la siguiente manera

struct 
{ 
    int x; 
    int y; 
} example_struct; 

es la estructura en la memoria de la example_struct simmilar a ese en Example_Class

por ejemplo, si hago lo siguiente

struct example_struct foo_struct; 
Example_Class foo_class = Example_Class(); 

memcpy(&foo_struct, &foo_class, sizeof(foo_struct)); 

foo_struct.x = 8 y foo_struct.y = 9 (es decir: ¿los mismos valores que los valores x, y en la clase_foo)?

La razón por la que pregunto es que tengo una biblioteca C++ (no quiero cambiarla) que está compartiendo un objeto con código C y quiero usar una estructura para representar el objeto proveniente de la biblioteca C++. Solo estoy interesado en los atributos del objeto.

Sé que la situación ideal sería tener un wrapper Example_class alrededor de una estructura común entre los códigos C y C++, pero no será fácil cambiar la biblioteca C++ en uso.

+5

Sólo un comentario menor, su constructor podría (y algunos dicen que debería) escribirse así: Example_Class(): x (8), y (9) {} – Dan

Respuesta

61

El C++ estándar garantías que los diseños de memoria de un C struct y un C++ class (o struct - misma cosa) será idéntico, siempre que el C++ class/struct se ajuste al criterio de ser POD ("Datos antiguos simples"). Entonces, ¿qué significa POD?

una clase o estructura es POD si:

  • Todos los miembros de datos son públicos y de ellos mismos POD o fundamentales tipos (pero no de referencia o tipos-puntero a miembro), o series de tales
  • Se no tiene constructores definidos por el usuario, operadores de asignación o destructores
  • no tiene funciones virtuales
  • no tiene clases base

Los únicos "ismos de C++" permitidos son funciones de miembros no virtuales, miembros estáticos y funciones de miembros.

Dado que su clase tiene tanto un constructor como un destructor, formalmente no es del tipo POD, por lo que la garantía no es válida. (Aunque, como han mencionado otros, en la práctica los dos diseños probablemente sean idénticos en cualquier compilador que pruebes, siempre que no haya funciones virtuales).

Ver la sección [26.7] de C++ FAQ Lite para más detalles.

+2

Dado que él está utilizando una biblioteca separada, yo diría que las diferencias en la configuración de la alineación de la estructura del compilador podrían haber existido cuando se compiló la biblioteca que podría causar diferencias en el diseño de la memoria. No es probable, pero es posible, parece. – moodboom

10

es la estructura en la memoria de la simmilar example_struct a la de Example_Class

El comportamiento no está garantizada, y es dependiente del compilador.

Habiendo dicho eso, la respuesta es "sí, en mi máquina", siempre que el Example_Class no contenga ningún método virtual (y no herede de una clase base).

+0

Sé que probablemente no debería hacer mi solución depende de la arquitectura, pero ¿qué máquina/compilador está utilizando? – hhafez

+0

compilador de Microsoft. – ChrisW

+0

Está garantizado en este ejemplo. – fabspro

7

En el caso que usted describe, la respuesta es "probablemente sí". Sin embargo, si la clase tiene funciones virtuales (incluido el destructor virtual, que podría heredarse de una clase base) o usa herencia múltiple, el diseño de la clase puede ser diferente.

2

que añadir a lo que han dicho otras personas (por ejemplo: compilador específico, es probable que trabajar todo el tiempo que no tiene funciones virtuales): cheque

I altamente sugeriría una aserción estática (en tiempo de compilación) que el tamaño de (Example_class) == sizeof (example_struct) si estás haciendo esto. Consulte BOOST_STATIC_ASSERT, o la construcción personalizada o compilador equivalente. Esta es una buena primera línea de defensa si alguien (o algo, como un cambio de compilador) modifica la clase para invalidar la coincidencia. Si desea una verificación adicional, también puede verificar que las compensaciones de los miembros sean las mismas, lo que (junto con la afirmación del tamaño estático) garantizará la corrección.

0

Las clases & las estructuras en C++ son el equivalente, excepto que todos los miembros de una estructura son públicos por defecto (los miembros de la clase son privados por defecto). Esto garantiza que la compilación de código C heredado en un compilador C++ funcionará como se espera.

No hay nada que nos impida el uso de todo el lujo C características ++ en una estructura:

struct ReallyAClass 
{ 
    ReallyAClass(); 
    virtual !ReallAClass(); 

    /// etc etc etc 
}; 
+0

Pensé que esta equivalencia solo significaba que puedes compilar código C como código C++ – user44511

+0

Son "equivalentes" de alguna manera, pero dudo (aunque no sé) si el estándar dice que sus diseños en memoria son idénticos ; además, tener un método "virtual" (como en su ejemplo defectuoso) ** probablemente cambiará el diseño (agregando un vptr a cada instancia). – ChrisW

+1

Todos los compiladores comunes colocan el puntero vtable al comienzo del objeto, por lo que tener un método virtual ** alterará ** el diseño de la memoria de la clase. C++ garantiza un comportamiento idéntico solo para los tipos POD ("Old Data"): una estructura o clase debe obedecer varias restricciones para clasificar como POD. –

0

¿Por qué no asignar explícitamente los miembros de la clase a la estructura cuando quiere pasar los datos a C? De esa forma sabrá que su código funcionará en cualquier lugar.

-2

Probablemente solo obtenga la clase de la estructura, ya sea pública o privadamente. Luego, al convertirlo se resolvería correctamente en el código de C++.

0

En los primeros días de los compiladores C++ había ejemplos cuando el compilador primero cambia las palabras clave struct con clase y luego compila. Demasiadas similitudes.

Las diferencias provienen de la herencia de clases y, especialmente, de las funciones virtuales. Si la clase contiene funciones virtuales, debe tener un puntero para escribir el descriptor al comienzo de su diseño. Además, si la clase B hereda de la clase A, entonces el diseño de la clase A es lo primero, seguido del diseño propio de la clase B.

Por lo tanto, la respuesta precisa a su pregunta sobre el solo lanzamiento de una instancia de clase a una instancia de estructura es: depende del contenido de la clase. Para la clase particular que tiene métodos (constructor y destructor no virtual), el diseño probablemente será el mismo. Si el destructor se declara virtual, el diseño definitivamente se volvería diferente entre estructura y clase.

Aquí está un artículo que demuestra que no hay mucho que se necesita para hacer el paso de las estructuras de C a C++ clases: Lesson 1 - From Structure to Class

y aquí está el artículo que explica cómo se introduce tabla de funciones virtuales de clases que tienen virtuales funciones: Lesson 4 - Polymorphism

Cuestiones relacionadas