2009-05-10 7 views
6

Considere el siguiente fragmento de código: -C-Style conversión hacia arriba y abatido que implica la herencia privada

class A {}; 

class B : private A {}; 

B* bPtr1 = new B; 
// A* aPtr1 = bPtr1; // error 
// A* aPtr2 = static_cast<A*>(bPtr1); // error 
A* aPtr3 = (A*)bPtr1; 
B* bPtr2 = (B*)aPtr3; 

La conversión de estilo C descarta la herencia privada mientras que tanto el implícito y static_cast fallan (también dynamic_cast). Por qué ? Si los moldes de estilo C solo están jugando un poco, ¿cómo se implementan los moldes de C++, es decir, cómo saben el tipo de herencia de la huella de memoria?

Después de que bPtr1 se transfiera a aPtr3, tendré que usar otro modelo C para bajar a B ya que de nuevo fallaron static_cast y dynamic_cast. Entonces, ¿está garantizado que bPtr2 sea bueno?

Gracias de antemano

+0

q relacionado (con una respuesta mejor): http://stackoverflow.com/questions/844816/c-style-upcast-and-downcast-involving-private-inheritance?rq=1 –

Respuesta

0

moldes El C++ son impuestas por el compilador (no el enlazador). No es que la herencia privada cause un diseño de clase diferente; es que el compilador le prohibirá arrojar un puntero a una clase derivada a un puntero a su clase base si la herencia no es pública, según la declaración de la clase.

-4

Si los moldes de estilo C solo están jugando un poco, ¿cómo se implementan los moldes de C++, es decir, cómo saben el tipo de herencia de la huella de memoria?

C-style castts en C++ significa más de lo que parece. Técnicamente, son la única forma de pedir al compilador que elija el operador de conversión correcto requerido para la conversión. Por la misma razón, esto es mejor que usar reinterpret_cast. El último es implementación definida.

Parece que hay mucha confusión en torno a los moldes de estilo C. Recuerde, ninguna herramienta es segura hasta que sepa cómo usarla. Lo mismo se aplica al molde de estilo C. El objetivo de tener un elenco de estilo C es pedirle al compilador que elija la conversión más segura y más portátil para un par de tipos dado. Esto puede desencadenar un cambio de static_cast a reinterpret_cast de forma silenciosa e introducir errores. El punto es: necesitas saber lo que estás haciendo.

+0

Gracias por hacerme saber el ' aspecto definido por la implementación 'de reinterpret_cast. – Abhay

+3

@dirkgently: Sí, los moldes estilo C le piden al compilador que elija el modelo correcto para ti, pero esto los hace ** peor ** que reinterpret_cast - al menos con reinterpret_cast, estás haciendo tu intención de hacer algo "malo" obvio (greppable de hecho), lo que facilita el mantenimiento. Se permite un elenco de estilo C y, a menudo, se realizará una reinterpretación_cast bajo el capó ** sin decirte **. -1. –

+0

Los yesos son arriesgados en el mejor de los casos. Por lo tanto, prefiero tener el compilador que elegir algo peor. Prefiero usar un elenco estilo C que reinterpretar_cast. – dirkgently

-1

Las respuestas existentes son grandes, pero un bit de información puede resultar de utilidad se refiere a esto:

moldes de tipo C son solo bit-jugueteando

Si utiliza un Antiguo- estilo entre dos tipos de punteros, el compilador normalmente no tendría que manipular ningún bit. Le está diciendo al compilador que desea tratar una ubicación de memoria como si contenga algún tipo (porque sabe que efectivamente lo hace), por lo que el compilador no hace nada en tiempo de ejecución para modificar el contenido de la memoria. La conversión simplemente desactiva la seguridad del tipo en tiempo de compilación.

+0

-1: tonterías. El uso de moldes de estilo C en C++ puede dar como resultado un 'reinterpret_cast', un' static_cast' o un 'const_cast' (o una combinación). Al menos uno de estos es, sin duda, más que "solo un poco de manipulación". –

+0

@LightnessRacesinOrbit Creo que esa es probablemente la razón por la que dije "normalmente no". –

7

Los estados estándar en 5.4.7 que los moldes de estilo C en realidad pueden hacer más que cualquier secuencia de lanzamientos de nuevo estilo pueden hacer - incluyendo específicamente de fundición a partir de un puntero a derivados de puntero-a-base incluso cuando la clase base es inaccesible, que es precisamente lo que sucede aquí con herencia privada. (Por qué debería permitirse esto, y en particular por qué debería permitirse solo para modelos de estilo C, está completamente más allá de mí, pero está innegablemente permitido).

Así que dribeas está en lo cierto, los compiladores están obligados a manejar los OP's C la conversión del puntero de estilo correctamente, incluso cuando B hereda de múltiples clases base.Mi propia prueba con MSVC++ 8 y MinGW confirma sus resultados en la práctica: cuando B hereda de múltiples clases base, el compilador ajustará los punteros al convertir un B* en un A* o viceversa para que se identifique el objeto o subobjeto correcto.

Me atengo a mi afirmación de que usted debe derivar Bpúblicamente de A si alguna vez la intención de tratar una B como A, ya que con la herencia privada en lugar hace necesario el uso de C-estilo arroja.

+1

Acabo de probarlo con gcc 4.0 en MacOSX y el código no se rompe. Llamar a un método virtual definido en A realmente llama a la versión B y el programa no muere. Si hay una conversión intermedia a void *, se llama erróneamente a la versión B de un método B virtual (el primer método en el vtable en mi prueba).Esto no quiere decir que no esté indefinido (no sé). Estoy de acuerdo en que los modelos de estilo C deben evitarse y que las versiones de C++ son más engorrosas para que se activen todas las alarmas, pero no puedo votar esta respuesta por el motivo anterior. –

+0

@dribeas: intrigante, voy a hacer algunas pruebas yo mismo en un momento. Una cosa: ¿tu X estaba vacía de elementos de datos? En ese caso particular, la Optimización de Base Vacía entraría en funcionamiento, permitiendo que el subobjeto A viva en la misma dirección que el objeto B. Pero si X contiene miembros de datos, creo que el subobjeto A no puede existir en la misma dirección, lo que lleva a la rotura. (En cualquier caso, esa arruga debería haberse mencionado en mi publicación.) –

+0

Bueno, es hora de comer un pastel humilde ... Resulta que el estándar establece que los moldes de estilo C pueden hacer * más que cualquier secuencia de estilo nuevo los moldes pueden hacer * en 5.4.7 - específicamente incluyendo la conversión de un puntero a derivado a un puntero a base incluso cuando la clase base es inaccesible, que es precisamente lo que sucede aquí con herencia privada. Así que dribeas tiene razón, los compiladores están obligados a realizar los ajustes de puntero necesarios para que el código que publique funcione. Mi propia prueba con MSVC++ 8 y MinGW confirma su prueba. –

Cuestiones relacionadas