2012-02-04 14 views
9

At a reply of a blog post of Raymond Chen,¿Por qué es importante utilizar static_cast en lugar de reinterpret_cast aquí?

Un interrogador señaló

Raymond, creo ejemplo el C++ no es correcta ya que la posición del subobjeto clase base en la clase derivada no se especifica de acuerdo con ISO C++ 2003 Standard (10-3, página 168), y supone que el subobjeto de clase base siempre está al principio. El ejemplo C también estaría bien en C++, así que me quedaría con él.

Raymond respondió

[El código no hace que esta suposición. Es por eso que es importante usar static_cast en lugar de reinterpret_cast. Pruébalo: agrega un método virtual a OVERLAPPED (para que un vtable vaya al frente) y observa lo que hace el compilador . -Raymond]

Pude adivinar después de leer sus comentarios. Usar static_cast está bien en el ejemplo pero reinterpret_cast no. Porque reinterpret_cast no es convertible vtable. ¿Lo entiendo bien?
Sin embargo, si utilizo el molde C-Style allí (no reinterpret_cast), ¿podría también salir mal?

He vuelto a leer Explicación del elenco de C++ más efectiva para comprender eso. Pero no hubo respuesta sobre eso.

+2

No soy versado en C++, pero tengo entendido que un "reinterpretar elenco" significa exactamente lo que '* (destination_type *) &' significaría en C. Presumiblemente, "elemental estático" realmente toma relaciones de clases en cuenta y permite al compilador realizar trabajos de conversión no triviales. –

Respuesta

17

El uso de static_cast está bien en el ejemplo pero reinterpret_cast no lo es. Porque reinterpret_cast no es convertible vtable.

No, el problema es que reinterpret_cast es completamente ajeno a la herencia. Simplemente devolverá la misma dirección sin cambios . Pero static_castsabe que está realizando un downcast: es decir, de conversión de una clase base a una clase derivada. Como conoce ambos tipos implicados, ajusta la dirección en consecuencia, es decir, hace lo correcto.

de pretender nuestra aplicación expone la hipotética clase OVERLAPPEDEX que tiene una función virtual como esto Let:

+------+------------+------------------+-------------+ 
| vptr | OVERLAPPED | AssociatedClient | ClientState | 
+------+------------+------------------+-------------+ 
    ^
     | 
     ptr 

El puntero que estamos puntos a la OVERLAPPED subobjeto dado. reinterpret_cast no cambiaría eso. Solo cambiaría el tipo. Obviamente, acceder a la clase OVERLAPPEDEX a través de esta dirección fácilmente causaría estragos, ¡porque las ubicaciones de sus subobjetos ahora están mal!

 what we believe we have when we access OVERLAPPEDEX through the pointer 
     +------+------------+------------------+-------------+ 
     | vptr | OVERLAPPED | AssociatedClient | ClientState | 
+------+------+-----+------+-----------+------+------+------+ 
| vptr | OVERLAPPED | AssociatedClient | ClientState | <- what we actually have 
+------+------------+------------------+-------------+ 
    ^
     | 
     ptr 

static_castsabe que para convertir una OVERLAPPED* a OVERLAPPEDEX* debe ajustar la dirección y hace lo correcto:

+------+------------+------------------+-------------+ 
| vptr | OVERLAPPED | AssociatedClient | ClientState | 
+------+------------+------------------+-------------+ 
^ 
| 
ptr after static_cast 

Aunque, si uso C-Style lanzar allí (no reinterpretar_cast), ¿podría también salir mal?

Una conversión de estilo C se define como la primera uno de los siguientes que tiene éxito:

  1. const_cast
  2. static_cast
  3. static_cast, entonces const_cast
  4. reinterpret_cast
  5. reinterpret_cast, luego const_cast

Como se puede ver, un static_cast es probado antes de reinterpret_cast, por lo que en este caso, una conversión de estilo C también haría lo correcto.


More info


no garantizados. Hay muy pocas garantías sobre lo que sucede en un reinterpret_cast. Todas las implementaciones que conozco simplemente darán la misma dirección sin cambios.

+0

Sí, mi 'convert vtable' era la frase más extraña. Por cierto, ¿el lanzador de estilo C también conoce la relación de herencia? Tal vez no lo es. Pero siempre he usado el elenco estilo C, incluso si uso C++. Y creo que incluso funcionó bien en el ejemplo. Eso es algo extraño. – Benjamin

+1

@Benjamin Agregué una explicación sobre los moldes de estilo C, y por qué funciona en este caso. Aunque recomendaría no usarlos, porque no siempre está claro cuál de las alternativas se elige. Un estuche estilo C es un martillo muy directo. –

+0

Por supuesto que seguiré su recomendación, porque ahora lo entiendo. Gracias. Sin embargo, ¿está normalizado el orden de los lanzadores C-Style? – Benjamin

Cuestiones relacionadas