tipos - try on c++
¿Por qué usar static_cast<int>(x) en lugar de(int) x? (9)
En resumen :
static_cast<>()
te da una capacidad de compilación de tiempo de compilación, el reparto C-Style no.static_cast<>()
puede verse fácilmente en cualquier lugar dentro de un código fuente de C ++; por el contrario, C_Style cast es más difícil de detectar.- Las intenciones se transmiten mucho mejor utilizando moldes de C ++.
Más explicación :
El reparto estático realiza conversiones entre tipos compatibles . Es similar al elenco de estilo C, pero es más restrictivo. Por ejemplo, la conversión de estilo C permitiría que un puntero entero apunte a un carácter.
char c = 10; // 1 byte int *p = (int*)&c; // 4 bytes
Dado que esto da como resultado un puntero de 4 bytes que apunta a 1 byte de la memoria asignada, escribir en este puntero causará un error en tiempo de ejecución o sobrescribirá alguna memoria adyacente.
*p = 5; // run-time error: stack corruption
En contraste con la conversión de estilo C, la conversión estática permitirá que el compilador compruebe que los tipos de datos de puntero y de punta son compatibles, lo que permite al programador detectar esta asignación de puntero incorrecta durante la compilación.
int *q = static_cast<int*>(&c); // compile-time error
Lea más en:
¿Cuál es la diferencia entre static_cast <> y estilo C casting
y
Reparto regular vs. static_cast vs. dynamic_cast
He escuchado que la función static_cast
debería preferirse a la static_cast
de estilo C o simple. ¿Es esto cierto? ¿Por qué?
- Permite que las conversiones se encuentren fácilmente en su código usando grep o herramientas similares.
- Hace que sea explícito el tipo de reparto que estás haciendo, y comprometer la ayuda del compilador para hacerla cumplir. Si solo desea eliminar la constancia, puede utilizar const_cast, que no le permitirá hacer otros tipos de conversiones.
- Los cast son intrínsecamente feos: usted como programador está ignorando cómo el compilador trataría normalmente su código. Le estás diciendo al compilador: "Sé mejor que tú". Siendo ese el caso, tiene sentido que realizar un reparto sea algo moderadamente doloroso, y que deberían sobresalir en su código, ya que son una fuente probable de problemas.
Ver la introducción efectiva de C ++
La pregunta es más grande que el uso de un casting de static_cast o de estilo C porque hay diferentes cosas que suceden cuando se usan moldes de estilo C. Los operadores de colada de C ++ están destinados a hacer estas operaciones más explícitas.
En la superficie, las transmisiones de static_cast y estilo C aparecen en la misma cosa, por ejemplo, cuando se envía un valor a otro:
int i;
double d = (double)i; //C-style cast
double d2 = static_cast<double>( i ); //C++ cast
Ambos de estos convierten el valor entero a un doble. Sin embargo, cuando se trabaja con punteros las cosas se vuelven más complicadas. algunos ejemplos:
class A {};
class B : public A {};
A* a = new B;
B* b = (B*)a; //(1) what is this supposed to do?
char* c = (char*)new int( 5 ); //(2) that weird?
char* c1 = static_cast<char*>( new int( 5 ) ); //(3) compile time error
En este ejemplo (1) tal vez esté bien porque el objeto al que apunta A es realmente una instancia de B. Pero, ¿qué sucede si no sabe en ese punto del código a qué apunta realmente? (2) tal vez perfectamente legal (solo desea mirar un byte del entero), pero también podría ser un error, en cuyo caso un error sería bueno, como (3). Los operadores de conversión de C ++ tienen la intención de exponer estos problemas en el código al proporcionar errores de tiempo de compilación o tiempo de ejecución cuando sea posible.
Por lo tanto, para una "conversión de valor" estricta puede usar static_cast. Si quieres un casting polimórfico en tiempo de ejecución de punteros usa dynamic_cast. Si realmente quiere olvidarse de los tipos, puede usar reintrepret_cast. Y para simplemente tirar const de la ventana hay const_cast.
Simplemente hacen que el código sea más explícito para que parezca que sabes lo que estabas haciendo.
La razón principal es que los modelos C clásicos no distinguen entre lo que llamamos static_cast<>()
, reinterpret_cast<>()
, const_cast<>()
y dynamic_cast<>()
. Estas cuatro cosas son completamente diferentes.
Un static_cast<>()
suele ser seguro. Existe una conversión válida en el idioma o un constructor apropiado que lo hace posible. La única vez que es un poco arriesgado es cuando desciende a una clase heredada; debe asegurarse de que el objeto sea en realidad el descendiente que dice que es, por medios externos al idioma (como una bandera en el objeto). Un dynamic_cast<>()
está seguro siempre que el resultado esté marcado (puntero) o se tenga en cuenta una posible excepción (referencia).
Un reinterpret_cast<>()
(o un const_cast<>()
) por otro lado siempre es peligroso. Le dices al compilador: "confía en mí: sé que esto no parece un foo
(parece que no es mutable), pero es".
El primer problema es que es casi imposible saber cuál ocurrirá en un reparto de estilo C sin mirar grandes piezas dispersas de código y conocer todas las reglas.
Asumamos estos:
class CMyClass : public CMyBase {...};
class CMyOtherStuff {...} ;
CMyBase *pSomething; // filled somewhere
Ahora, estos dos están compilados de la misma manera:
CMyClass *pMyObject;
pMyObject = static_cast<CMyClass*>(pSomething); // Safe; as long as we checked
pMyObject = (CMyClass*)(pSomething); // Same as static_cast<>
// Safe; as long as we checked
// but harder to read
Sin embargo, veamos este código casi idéntico:
CMyOtherStuff *pOther;
pOther = static_cast<CMyOtherStuff*>(pSomething); // Compiler error: Can''t convert
pOther = (CMyOtherStuff*)(pSomething); // No compiler error.
// Same as reinterpret_cast<>
// and it''s wrong!!!
Como puede ver, no hay una manera fácil de distinguir entre las dos situaciones sin saber mucho sobre todas las clases involucradas.
El segundo problema es que los modelos de estilo C son demasiado difíciles de localizar. En expresiones complejas puede ser muy difícil ver moldes de estilo C Es virtualmente imposible escribir una herramienta automatizada que necesita ubicar conversiones de estilo C (por ejemplo, una herramienta de búsqueda) sin un front-end completo de compilador de C ++. Por otro lado, es fácil buscar "static_cast <" o "reinterpret_cast <".
pOther = reinterpret_cast<CMyOtherStuff*>(pSomething);
// No compiler error.
// but the presence of a reinterpret_cast<> is
// like a Siren with Red Flashing Lights in your code.
// The mere typing of it should cause you to feel VERY uncomfortable.
Eso significa que, no solo los lanzamientos de estilo C son más peligrosos, sino que es mucho más difícil encontrarlos todos para asegurarse de que sean correctos.
Los moldes estilo C son fáciles de perder en un bloque de código. Los modelos de estilo C ++ no solo son una mejor práctica; Ofrecen un grado mucho mayor de flexibilidad.
reinterpret_cast permite conversiones de tipo puntero integrales, sin embargo, puede ser inseguro si se utiliza incorrectamente.
static_cast ofrece una buena conversión para tipos numéricos, por ejemplo, desde enumeraciones a ints o ints a flotantes o cualquier tipo de datos que confíe en el tipo. No realiza ninguna verificación de tiempo de ejecución.
Dynamic_cast, por otro lado, realizará estas comprobaciones marcando cualquier asignación o conversión ambigua. Solo funciona con punteros y referencias e incurre en una sobrecarga.
Hay un par de otros, pero estos son los principales que encontrarás.
Se trata de cuánta seguridad de tipos quieres imponer.
Cuando escribe (bar) foo
(que es equivalente a reinterpret_cast<bar> foo
si no ha proporcionado un operador de conversión de tipos) le está diciendo al compilador que ignore la seguridad de tipos, y simplemente haga lo que se le indique.
Cuando escribe static_cast<bar> foo
le está pidiendo al compilador que al menos compruebe que la conversión de tipo tiene sentido y, para los tipos integrales, que inserte algún código de conversión.
EDITAR 2014-02-26
Escribí esta respuesta hace más de 5 años, y me equivoqué. (Ver comentarios). ¡Pero todavía se pone a la altura!
Un consejo pragmático: puede buscar fácilmente la palabra clave static_cast en su código fuente si planea ordenar el proyecto.
static_cast, además de manipular los punteros a las clases, también se puede utilizar para realizar conversiones definidas explícitamente en clases, así como para realizar conversiones estándar entre tipos fundamentales:
double d = 3.14159265;
int i = static_cast<int>(d);
static_cast
significa que no puedes accidentalmente const_cast
o reinterpret_cast
, lo cual es bueno.