2011-10-14 8 views
9

Digamos que tengo dos clases diferentes, ambos representan 2D datos de coordenadas de la misma manera interna como la siguiente:seguridad de la fundición entre los punteros de dos clases idénticas?

class LibA_Vertex{ 
    public: 
    // ... constructors and various methods, operator overloads 
    float x, y 
}; 

class LibB_Vertex{ 
    public: 
    // ... same usage and internal data as LibA, but with different methods 
    float x, y 
}; 


void foobar(){ 
    LibA_Vertex * verticesA = new LibA_Vertex[1000]; 
    verticesA[50].y = 9; 
    LibB_Vertex * verticesB = reinterpret_cast<LibB_Vertex*>(vertexA); 
    print(verticesB[50].y); // should output a "9" 
}; 

Teniendo en cuenta las dos clases que son idénticos y la función anterior, puedo fiable contar con esta conversión puntero trabajando como se espera en todos los casos?

(El trasfondo es que necesito una forma fácil de intercambiar matrices de vértices entre dos bibliotecas separadas que tienen clases Vértice idénticas, y quiero evitar la innecesaria copia de matrices).

Respuesta

13

C++ 11 agregó un concepto llamado compatible con el diseño que se aplica aquí.

Dos estándar diseño estructura (Cláusula 9) tipos se diseño compatible si tienen el mismo número de miembros de datos no estáticos y los miembros de datos no estáticos correspondientes (en orden de la declaración) tienen compatible con la disposición tipos (3.9).

donde

una clase estándar-layout es una clase que:

  • no tiene miembros de datos no estáticos de la clase de tipo no estándar-layout (o conjunto de tales tipos) o de referencia,
  • no tiene funciones virtuales (10.3) y no hay clases base virtuales (10.1),
  • tiene el mismo control de acceso (Cláusula 11) para todos no estático de datos m aster,
  • no tiene clases base de diseño no estándar,
  • tampoco tiene miembros de datos no estáticos en la clase más derivada y como máximo una clase base con miembros de datos no estáticos, o no tiene clases base con no estático miembros de datos, y
  • no tiene clases base del mismo tipo que el primer miembro de datos no estático.

A struct estándar-layout es una clase estándar-layout definida con la clave de clase struct o la clave de clase class.

Una unión estándar diseño es una clase estándar -diseño definido con la clase de claveunion.

Finalmente

Punteros a CV-calificado y no calificado versiones CV-(3.9.3) de diseño compatible con tipos tendrán los mismos requisitos de representación de valor y de alineación (3.11).

Lo que garantiza que reinterpret_cast puede convertir un puntero a un tipo en un puntero a cualquier tipo de diseño compatible.

+3

Otra forma bien definida de hacer estas conversiones es usar una unión con una secuencia inicial común (como lo permite el '§9.2/19'). – Mankarse

+0

¡Oh! Bueno, C++ 11 al rescate. Solo espero que esta sea una de las cosas que VS2010 decidió agregar cuando salió a relucir el estándar. –

+1

@Clairvoire: Esta es una de las cosas que siempre funcionó en la práctica, a pesar de estar prohibido formalmente. No espero que ningún escritor de compiladores tenga que "agregar" soporte. –

1

me envuelva que la conversión en una clase (de modo que si usted necesita cambiar la plataforma o algo así, está localizada al menos en un punto), pero sí que debería ser posible.

Querrá utilizar reinterpret_cast, no static_cast también.

+0

Correcto, mi error! Se corrigió la pregunta –

1

Teóricamente, este es un comportamiento indefinido. Sin embargo, puede funcionar en ciertos sistemas/plataformas.

Yo sugeriría que usted debe tratar de fusionar 2 clases en 1. decir

class Lib_Vertex{ 
// data (which is exactly same for both classes) 
public: 
// methods for LibA_Vertex 
// methods for LibB_Vertex 
}; 

métodos de agregarlo a una class no afectará a su tamaño. Puede que tenga que cambiar un poco su diseño, pero vale la pena.

+0

Normalmente, usaría algo como esto también. Aun así, tendría que hacer copias de los arreglos. Una biblioteca (2d physics lib) devuelve matrices enteras de vértices usando su clase Vertex interna, que luego necesito alimentar a la otra biblioteca (2d rendering lib) que acepta matrices de su clase interna de Vertex. –

0

Técnicamente esto es un comportamiento indefinido. En realidad, si se utilizó el mismo compilador para compilar ambas clases, tendrán el mismo diseño en la memoria si los campos se declaran en el mismo orden, tienen los mismos tipos y el mismo nivel de acceso.

Cuestiones relacionadas