moldes de estilo c o moldes de estilo c ++

21

Entonces, ¿qué usas?

int anInt = (int)aFloat;

o

int anInt = static_cast<int>(aFloat);
// and its brethren

Y, lo que es más importante, ¿por qué?

Bastibe
fuente

Respuestas:

45

Primero, comprenda que esas líneas no son equivalentes .

int* anInt = (int*)aFloat; // is equivalent to

int* anInt = reinterpret_cast<int*>(aFloat); 

Lo que está sucediendo aquí es que el programador le está pidiendo al compilador que haga todo lo posible para hacer el reparto.

La diferencia es importante porque usar static_cast solo pedirá un tipo base que sea "seguro" para convertir, donde reinterpret_cast se convertirá a cualquier cosa, posiblemente simplemente mapeando el diseño de memoria deseado sobre la memoria del objeto dado.

Por lo tanto, como el "filtro" no es el mismo, el uso de una conversión específica es más claro y seguro que el uso de la conversión C, si confía en el compilador (o tiempo de ejecución implícito si usa Dynamic_cast) para decirle dónde hizo algo mal , evitando el lanzamiento de C y reinterepret_cast.

Ahora que esto está más claro, hay otra cosa: static_cast, reinterpret_cast, const_cast y dynamic_cast son más fáciles de buscar .

Y el punto final: son feos . Eso es buscado. El código potencialmente defectuoso, los olores de código, los "trucos" obvios que pueden generar errores, son más fáciles de rastrear cuando se asocia con un aspecto feo. El código incorrecto debería ser feo .

Eso es "por diseño". Y eso le permite al desarrollador saber dónde podría haber hecho las cosas mejor (evitando totalmente los lanzamientos, si no es realmente necesario) y dónde está bien, pero está "documentado" en el código al "marcarlo" como feo.

Una razón secundaria para presentar el elenco de nuevo estilo fue que los elencos de estilo C son muy difíciles de detectar en un programa. Por ejemplo, no puede buscar cómodamente los moldes utilizando un editor ordinario o un procesador de textos. Esta casi invisibilidad de los modelos de estilo C es especialmente desafortunada porque son potencialmente dañinos. Una operación fea debe tener una forma sintáctica fea. Esa observación fue parte de la razón para elegir la sintaxis de los moldes de nuevo estilo. Otra razón fue que los modelos de nuevo estilo coincidían con la notación de plantilla, de modo que los programadores pueden escribir sus propios modelos, especialmente los modelos de tiempo de ejecución verificado.

Tal vez, debido a que static_cast es tan feo y relativamente difícil de escribir, ¿es más probable que lo pienses dos veces antes de usar uno? Eso sería bueno, porque los moldes realmente son evitables en C ++ moderno.

Fuente: Bjarne Stroustrup (creador de C ++)

Klaim
fuente
2
Lo rechazaría si tuviera algunos puntos más, pero desafortunadamente no puedo. Los lanzamientos de estilo c NO son equivalentes a reinterpret_cast. Considere reinterpret_cast<int>(double);. Es completamente posible lanzar un doble a un int con un reparto de estilo c, pero no es posible hacerlo con reinterpret_cast. Veo que Timbo ya te señaló esto y dijiste que lo arreglarías, pero cuatro años después sigue siendo incorrecto. Sin embargo, todavía te votaría si eso se solucionara, ya que hay razones perfectamente válidas para usar un yeso. Aquí hay una mejor respuesta: stackoverflow.com/a/332086/3878168
Yay295
36

Los moldes de C ++ son más restrictivos (así que expresa mejor tu intención y facilita la revisión del código, etc.). También son mucho más fáciles de buscar, si alguna vez lo necesita.

Bruce Stephens
fuente
10
... y es más probable que hagan lo que pretendes. ;-)
Macke
77
Y son mucho más para escribir, lo que le da una razón más para simplemente corregir sus tipos sin necesidad de yesos.
Michael Kohne
77
Y son feos como característica, lo que hace obvio dónde en el código puede haber puntos de mejora o casos especiales que pueden requerir documentación. - editar: ¡guau, acabo de descubrir que también respondí esta pregunta! XD
Klaim
Ahora, ¿por qué querría buscarlos?
Deduplicador
@Dupuplicator Hay muchas razones por las que es posible que desee saber dónde están ocurriendo los lanzamientos en una base de código. Por ejemplo, al buscar errores que podrían estar asociados con la transmisión (en particular, cuando se realiza el desarrollo multiplataforma).
Klaim
13

Opción C: un reparto de "estilo C ++", porque no se puede distinguir de una construcción:

int anInt = int(aFloat);

o incluso:

int anInt(aFloat);

Aparte de eso, aparte de estos casos triviales con primitivas, que se entienden bien, prefiero usar x_cast <> s sobre los lanzamientos de estilo C. Hay tres razones por las cuales:

  • Definen más estrechamente la operación que el programador intentaba realizar.

  • Pueden realizar acciones que las conversiones de estilo C no pueden (especialmente en el caso de dynamic_cast <>, que puede realizar una conversión cruzada en las ramas de una cadena de herencia múltiple).

  • Son feos . Declaran en voz alta que el programador está trabajando contra el sistema de tipos. En este caso, es algo bueno .

Dragón Kaz
fuente
7

Si escribe código en C, use un elenco en C. Si escribe en C ++, use un molde de C ++.

Si bien la mayoría de los lanzamientos rompen con la seguridad de tipo adecuada, los de C ++ son más restrictivos y, por lo tanto, usted es un poco menos inseguro de lo que sería con un yeso en C.

Aunque puedo tolerar que alguien use (T *) NULL para forzar una sobrecarga ...

CashCow
fuente
7

Tengo algunas reglas sobre los moldes de estilo C / C ++:

  1. Desaplicar una constante siempre debe usar a const_cast. Por obvias razones. Lamentablemente, mi regla sobre la desaplicación de una constante que hace que el teclado alcance y rompa el dedo del programador no fue aprobada.
  2. Debería usar cualquiera de las travesuras de estilo de manipulación de bits que los programadores hacen al bajar al metal reinterpret_cast. Realmente es el tipo de elenco que C no tiene: fingir que los bits de este entero son en realidad bits de flotante. Esto evita desagradables como (int)(*(int*)(&floatVar)).
  3. Si escribe las palabras " dynamic_cast", pare y vuelva a evaluar su jerarquía y diseño de clase polimórfica. Continúe reevaluando el diseño de su jerarquía de clases hasta que pueda eliminar esas palabras.
  4. No te molestes con static_cast.

El razonamiento detrás del # 4 es simplemente que no importa. Las circunstancias que no se ajustan a las otras reglas son obvias o realmente de bajo nivel. Una conversión bien entendida de tipos simples como int-to-float no debería necesitar una sintaxis especial. Y si estás en las entrañas profundas y feas de algo, bueno, estás en las entrañas profundas y feas de algo. No hay necesidad de llamar la atención sobre el hecho de que "aquí habrá dragones", ya que los dientes, las garras y el fuego ya lo delataron.

Nicol Bolas
fuente
1
dynamic_castEs una herramienta perfectamente válida. Raramente útil, lo admito, pero está lejos del Satanás de cosas como las variables globales. Sin embargo, principalmente, te rechacé porque no respondiste la pregunta , que se refería al uso o no de los modelos de estilo C.
DeadMG
2
@DeadMG: hablé sobre los elencos de estilo C. Todo el último párrafo justifica los lanzamientos de estilo C a favor de static_cast.
Nicol Bolas
"Lamentablemente, mi regla sobre la desaplicación de una constante que hace que el teclado se levante y rompa el dedo del programador no fue aprobada". Técnicamente, en realidad es legal que el compilador haga que eso suceda. Como es legal para el compilador hacer que los demonios vuelen de tu nariz .
Pharap
3

Realmente depende del idioma con el que estoy trabajando, ya que sabes lo que dicen: en Roma hablas romano. Entonces, si estoy programando en C, trato de usar las características de C al máximo, pero si estoy programando en C ++, sigo adelante y uso las funciones de C ++ al máximo, incluso si a algunas personas no les gusta ese enfoque porque dicen que hace que el código sea "menos portátil", digo que no me importa, estoy en C ++ y programando en C ++, y necesito un compilador totalmente compatible con C ++ para compilar código, de lo contrario estaría trabajando con algo diferente en primer lugar.

Coyote21
fuente
Realmente no funciona tratar de usar moldes de estilo C ++ en C ;-)
Steve314
3

static_cast, etc.se inventaron debido a problemas con los moldes de estilo C cuando se usan en plantillas. Si está escribiendo una plantilla, o si su código se puede convertir más tarde en una plantilla, es una buena idea usar moldes de estilo C ++. La razón es porque los lanzamientos de estilo C ++ expresan mejor la intención, por lo que darán los resultados esperados en los casos en que los lanzamientos de estilo C hagan lo incorrecto (dados tipos particulares como parámetros de plantilla).

Aparte de eso, digo que use transmisiones de estilo C ++ si tiene un problema específico que las necesita: dynamic_cast es el más común, pero incluso eso probablemente no sea algo cotidiano.

Cualquier otra cosa, y un elenco de estilo C puede ser un poco menos desordenado y ayudar a la legibilidad, o tal vez no dependiendo de qué tan familiarizado esté el lector con ese estilo de elenco en estos días. En mi opinión, no es realmente importante, sobre todo una cuestión de preferencia personal, aunque no se sorprenda si a algunas personas no les gusta el estilo C.

Nota final: si necesita tantos lanzamientos que esto es un gran problema, probablemente esté haciendo algo más mal. Hay excepciones a eso en algunos casos, pero la mayoría del código de alto nivel no debería necesitar muchos (si los hay) lanzamientos.

Steve314
fuente