2010-04-10 9 views
13

He estado leyendo StackOverflow demasiado y comencé a dudar de todo el código que he escrito, sigo pensando "¿Es ese comportamiento indefinido?" incluso en código que ha estado funcionando durante años.Puntero de fundición para objetar a void * en C++

Así que mi pregunta - ¿Es seguro y bien definido comportar arrojar un puntero a un objeto (en este caso clases de interfaz abstractas) a un vacío * y luego volverlos a la clase original y llamar al método usándolos ?

Soy totalmente consciente de que el código que hace esto es probablemente horrible. Ni siquiera consideraría escribirlo así ahora (este es un código antiguo que realmente no quiero cambiar), así que no estoy buscando una discusión sobre mejores formas de hacerlo. Ya sé cómo escribirlo mejor si vuelvo a hacerlo. Pero si realmente está roto para confiar en esto en C++ entonces tendré que considerar cambiar el código, si es simplemente un código horrible, entonces cambiarlo no será una prioridad.

No tenía dudas sobre algo tan simple hace un año o dos, pero a medida que mi comprensión de C++ aumenta, me doy cuenta de que cada vez me preocupo más por la seguridad del código incluso si funciona perfectamente. Tal vez demasiada importancia desbordamiento de pila es algo malo para la productividad veces: P

Respuesta

16

Estás seguro.

De C++ (0x) proyecto,

§ 5.2.9/13 (por static_cast):

Un valor de tipo puntero a objeto convertido a “puntero a cvvoid” y volver, posiblemente con diferente calificación cv, tendrá su valor original.

§ 5.2.10/7 (para reinterpret_cast):

la conversión de un valor p de tipo “puntero a T1” para el tipo “puntero a T2” (donde T1 y T2 son tipos de objetos y donde los requisitos de alineación de T2 no son más estrictos que los de T1) y volver a su tipo original produce el valor del puntero original.

(Por supuesto, la conversión a una clase no relacionada es un comportamiento indefinido.)

+1

Si bien este comportamiento no cambia en C++ 0x, no creo que sea una buena práctica citar un borrador de estándar no aceptado para responder preguntas sobre el estado actual del idioma. –

+0

Gracias. Me siento bastante estúpido al hacer una pregunta tan básica después de 10 años de programación en C++, pero cuanto más aprendo sobre C++ más dudo de mí mismo a veces. Alguien mas se siente de esa manera? ... Hmm, solo yo entonces. – jcoder

8

Así que mi pregunta - ¿Es seguro y behavour bien definido para convertir un puntero a un objeto (en este caso las clases de interfaz abstracta) a un vacío * y luego, más tarde, vuelve a enviarlos a la clase original y llama al método para usarlos.

Sí - siempre y cuando lanzas de nuevo a la exactamente el mismo tipo. De lo contrario, los ajustes del puntero de la clase base pueden destruir el valor del puntero.

En la práctica, esto es (probablemente) sólo es relevante cuando se utiliza la herencia múltiple: punteros a una clase derivada pueden diferir en su dirección física de punteros a su clase base.

1

Utilizamos esta técnica comúnmente para no tener instrucciones switch en cada clase única basada en el entorno que esté utilizando (basado en la Web, Windows, Linux, etc.)

Uso void ** referencias.

void ** detailObject; 

crear una función para devolver el objeto referenciado:

TheObject *TheClass::GetObject(){ 
    TheObject *object = (TheObject*)object; 
    return object; 
} 

sólo tiene que utilizar la función como el objeto de ahora en adelante. p.ej. GetObject()->Go();