2010-06-15 8 views
10

Mi conocimiento de C++ en este momento es más académico que cualquier otra cosa. En toda mi lectura hasta el momento, el uso de conversiones explícitas con los modelos electos (const_cast, static_cast, reinterpret_cast, dynamic_cast) viene con una gran etiqueta de advertencia (y es fácil ver por qué) que implica que la conversión explícita es sintomática de un mal diseño y solo debe usarse como último recurso en circunstancias desesperadas. Entonces, tengo que preguntar:¿La conversión explícita de C++ es realmente tan mala?

¿La conversión explícita con yesos con nombre es realmente solo un código de montaje de jurado o hay una aplicación más elegante y positiva a esta función? ¿Hay un buen ejemplo de esto último?

Respuesta

19

Hay casos en los que no se puede pasar sin él. Me gusta this one. El problema es que tiene herencia múltiple y necesita convertir el puntero this en void* mientras se asegura de que el puntero que entra en void* aún apuntará al subobjeto derecho del objeto actual. Usar un lanzamiento explícito es la única forma de lograr eso.

Existe la opinión de que si no puede pasar sin un yeso tiene un mal diseño. No puedo estar de acuerdo con esto por completo, son posibles diferentes situaciones, incluida una mencionada anteriormente, pero tal vez si necesita utilizar moldes explícitos con demasiada frecuencia, realmente tiene un mal diseño.

+9

Estoy de acuerdo con el comentario final de sharptooth aquí, el hecho de que tengas un elenco explícito no significa que tengas un código incorrecto, pero si estás lanzando hacia atrás y hacia delante cada dos líneas, entonces necesitas replantear las cosas. Casting es una operación válida, pero es algo que no debería usarse en exceso. –

+1

¡Ciertamente nunca solía arrojar advertencias y errores de compilación! – Alan

11

Hay situaciones en las que no se pueden evitar los moldes explícitos. Especialmente cuando se interactúa con bibliotecas C o bibliotecas C++ mal diseñadas (como la biblioteca COM usada como ejemplos de sharptooth).

En general, el uso de moldes explícitos ES una pista falsa. No necesariamente significa un código incorrecto, pero llama la atención sobre un posible uso peligroso.

Sin embargo no se debe tirar los 4 moldes en la misma bolsa: static_cast y dynamic_cast se utilizan con frecuencia para un máximo de fundición a presión (desde la base hasta Derivado) o para navegar entre los tipos relacionados. Su aparición en el código es bastante normal (de hecho, es difícil escribir un patrón Visitor sin ninguno).

Por otro lado, el uso de const_cast y reinterpret_cast es mucho más peligroso.

  • usando const_cast para tratar de modificar un objeto de sólo lectura es un comportamiento indefinido (gracias a James McNellis para la corrección)
  • reinterpret_cast normalmente sólo se utiliza para hacer frente a la memoria prima (colocadores)

Tienen su uso, por supuesto, pero no deberían encontrarse en el código normal. Sin embargo, para tratar con API externas o C, pueden ser necesarias.

Al menos esa es mi opinión.

+1

Técnicamente solo modifica _ un objeto de solo lectura a través del resultado de un 'const_cast' que da como resultado un comportamiento indefinido. El 'const_cast' en sí mismo es" seguro ". –

+0

Gracias, modifiqué la oración en consecuencia. Efectivamente, cualquier lanzamiento es seguro en sí mismo, solo usa el resultado que puede invocar un comportamiento indefinido. –

+0

COM no es una biblioteca C++ y, por lo tanto, no se diseñó con una buena semántica de C++ en mente. Esto no lo hace malo: simplemente define su propio modelo de objetos. (COM es un PITA por * otros * motivos) –

3

IMO, como la mayoría de las cosas, son herramientas, con usos apropiados e inapropiados. Casting es probablemente un área donde las herramientas se usan con frecuencia de manera inapropiada, por ejemplo, para lanzar entre int y un tipo de puntero con reinterpret_cast (que puede romperse en plataformas donde los dos son de diferentes tamaños) o const_cast constness puramente como un hack , y así.

Si sabe para qué sirven y los usos previstos, no hay absolutamente nada de malo en usarlos para lo que fueron diseñados.

6

La gravedad de un yeso depende típicamente del tipo de yeso. Existen usos legítimos para todos estos moldes, pero algunos huelen peor que otros.

const_cast se utiliza para descartar const ness (ya que no necesita escayolar). Idealmente, eso nunca debería ser usado. Hace que sea fácil invocar un comportamiento indefinido (tratando de cambiar un objeto originalmente designado como const) y, en cualquier caso, rompe el const -corrección del programa. A veces es necesario cuando se interactúa con API que no son en sí mismas const -correcta, que pueden, por ejemplo, pedir un char * cuando van a tratarlo como const char *, pero dado que no debería escribir API de esa manera, es una señal de que está usando una API realmente vieja o alguien está jodido.

reinterpret_cast siempre dependerá de la plataforma y, por lo tanto, es cuestionable en el código portátil. Además, a menos que esté haciendo operaciones de bajo nivel en la estructura física de los objetos, no preserva el significado. En C y C++, se supone que un tipo es significativo. Un int es un número que significa algo; un int que es básicamente la concatenación de char s realmente no significa nada.

dynamic_cast se utiliza normalmente para downcasting; p.ej. desde Base * hasta Derived *, con la condición de que o bien funciona o devuelve 0. Esto subvierte OO de forma muy similar a como lo hace una declaración switch en una etiqueta de tipo: mueve el código que define qué clase está fuera de la definición de clase . Esto combina las definiciones de clase con otro código y aumenta la carga de mantenimiento potencial.

static_cast se utiliza para las conversiones de datos que generalmente se consideran correctas, como las conversiones ay desde void *, conocidos bloqueos de punteros seguros dentro de la jerarquía de clases, ese tipo de cosas. Lo peor que puedes decir es que subvierte el sistema de tipo hasta cierto punto. Es probable que sea necesario cuando se hace interfaz con bibliotecas C, o la parte C de la biblioteca estándar, ya que void * se usa a menudo en funciones C.

En general, código C++ bien diseñado y bien escrito evitará los casos de uso anteriores, en algunos casos porque el único uso del molde es hacer cosas potencialmente peligrosas, y en otros casos porque dicho código tiende a evitar la necesidad de tales conversiones. El sistema de tipo C++ generalmente se considera como algo bueno de mantener, y lo convierte en subversivo.

1

Hay ironía en los moldes explícitos. El desarrollador cuyas habilidades de diseño pobres en C++ lo llevan a escribir código que requiere mucho casting es el mismo desarrollador que no usa los mecanismos de lanzamiento explícitos de manera apropiada, o en absoluto, y ensucia su código con moldes de estilo C.

Por otro lado, el desarrollador que entiende su propósito, cuándo usarlos y cuándo no, y cuáles son las alternativas, ¡no está escribiendo código que requiere mucho casting!


Mira la más variaciones de grano fino en estos moldes, como polymorphic_cast, en la biblioteca de conversiones de impulso, para darle una idea de qué tan cuidadoso C++ programadores son cuando se trata de la fundición.

1

Los moldes son un signo de que estás tratando de poner una clavija redonda en un agujero cuadrado. A veces eso es parte del trabajo. Pero si usted tiene cierto control sobre el agujero y la clavija, sería mejor no crear esta condición, y escribir un yeso debería hacer que se pregunte si había algo que podría haber hecho así que esto fue un poco más suave.

Cuestiones relacionadas