¿Cuándo deben utilizarse static_cast, dynamic_cast, const_cast y reinterpret_cast?

¿Cuál es el uso adecuado?

  • static_cast
  • dynamic_cast
  • const_cast
  • reinterpret_cast
  • (type)value estilo C (type)value
  • type(value) estilo casting

¿Cómo decides qué usar en qué casos?

2153
01 дек. fijado por e.James 01 dic. 2008-12-01 23:11 '08 a las 11:11 pm 2008-12-01 23:11
@ 8 respuestas

static_cast es el primer lanzamiento que deberías intentar usar. Hace cosas como conversiones implícitas entre tipos (por ejemplo, de int a float o un puntero a void* ), y también puede llamar a funciones de conversión explícitas (o implícitas). En muchos casos, static_cast no se establece explícitamente, pero es importante tener en cuenta que la sintaxis T(something) equivalente a (T)something , y debe evitarse (más sobre esto más adelante). A T(something, something_else) es seguro y, sin embargo, garantiza llamar al constructor.

static_cast también se puede realizar a través de jerarquías de herencia. Esto no es necesario cuando se lanza hacia arriba (hacia la clase base), pero al soltarlo se puede usar hasta que se herede virtual herencia virtual . Sin embargo, la validación no se realiza y el comportamiento no definido con static_cast en la jerarquía es de un tipo que no es realmente un tipo de objeto.


const_cast se puede usar para eliminar o agregar const a una variable; ningún otro método de C ++ puede eliminarlo (ni siquiera reinterpret_cast ). Es importante tener en cuenta que un cambio en el valor anterior de const solo está indefinido si la variable inicial const ; Si lo usa para eliminar un enlace const a algo que no se declaró usando const , es seguro. Esto puede ser útil, por ejemplo, cuando se sobrecargan funciones miembro basadas en const . También se puede usar para agregar const a un objeto, por ejemplo, para llamar a una sobrecarga de una función miembro.

const_cast también funciona de manera similar a volatile , aunque esto es menos común.


dynamic_cast utiliza casi exclusivamente para procesar polimorfismo. Puede superponer un puntero o un enlace a cualquier tipo polimórfico en cualquier otro tipo de clase (un tipo polimórfico tiene al menos una función virtual declarada o heredada). Puede usarlo más que simplemente tirarlo, puede tirarlo de lado o incluso otra cadena. dynamic_cast buscará el objeto deseado y, si es posible, lo devolverá. Si no puede, devolverá nullptr en el caso de un puntero, o lanzará std::bad_cast en el caso de un enlace.

dynamic_cast tiene algunas limitaciones. No funciona si hay varios objetos del mismo tipo en la jerarquía de herencia (el llamado "diamante de miedo") y no utiliza virtual herencia virtual . También puede pasar solo a través de la herencia pública; siempre se llevará protected o private través de la herencia. Esto rara vez es un problema, ya que tales formas de herencia son raras.


reinterpret_cast es el lanzamiento más peligroso y debe usarse con moderación. Convierte un tipo directamente en otro, por ejemplo, descartando un valor de un puntero a otro o guardando el puntero en un int o todo tipo de otras cosas desagradables. Básicamente, la única garantía que obtiene con reinterpret_cast es que, por lo general, si devuelve el resultado al tipo original, obtendrá el mismo valor (pero no si el tipo intermedio es más pequeño que el tipo original). Hay una serie de transformaciones que reinterpret_cast no puede realizar. Se usó principalmente para transformaciones y manipulaciones particularmente extrañas con bits, como convertir el flujo de datos sin procesar en datos reales o almacenar los datos en los bits más bajos del puntero alineado.


La lista de estilos <style>> es un (type)object o type(object) respectivamente. Una lista de estilo C se define como la primera de las siguientes, que tiene éxito:

  • const_cast
  • static_cast (aunque ignora las restricciones de acceso)
  • static_cast (ver arriba), luego const_cast
  • reinterpret_cast
  • reinterpret_cast , luego const_cast

En algunos casos, se puede usar como un sustituto de otros fantasmas, pero puede ser extremadamente peligroso debido a la capacidad de entrar en un reinterpret_cast , y este último debe ser preferido cuando se requiere un lanzamiento explícito si no está seguro de que static_cast tenga éxito o reinterpret_cast terminará con por error Incluso entonces considere una opción más larga, más explícita.

Los static_cast estilo C también ignoran el control de acceso al realizar static_cast , lo que significa que tienen la capacidad de realizar una operación que ningún otro lanzamiento puede realizar. Esto se debe principalmente a la confusión, y en mi opinión, esta es otra razón para evitar un reparto de estilo C.

2286
01 дек. La respuesta se da coppro 01 dec. 2008-12-01 23:26 '08 a las 11:26 pm 2008-12-01 23:26

Use dynamic_cast para convertir los punteros / enlaces a la jerarquía de herencia.

Utilice static_cast para conversiones de tipos regulares.

Utilice reinterpret_cast para la reinterpret_cast de bajo nivel de patrones de bits. Utilizar con extrema precaución.

Usa const_cast para soltar const/volatile . Evita esto si no estás atascado usando una API incorrecta.

298
01 дек. Respuesta dada por Fred Larson 01 dic. 2008-12-01 23:22 '08 a las 11:22 2008-12-01 23:22

(Muchas explicaciones teóricas y conceptuales fueron dadas arriba)

A continuación se muestran algunos ejemplos prácticos cuando utilicé static_cast , dynamic_cast , const_cast , reinterpret_cast .

(También se refiere a esto para entender la explicación: http://www.cplusplus.com/doc/tutorial/typecasting/ )

static_cast:

 OnEventData(void* pData) { ...... // pData is a void* pData, // EventData is a structure eg // typedef struct _EventData { // std::string id; // std:: string remote_id; // } EventData; // On Some Situation a void pointer *pData // has been static_casted as // EventData* pointer EventData *evtdata = static_cast<EventData*>(pData); ..... } 

dynamic_cast:

 void DebugLog::OnMessage(Message *msg) { static DebugMsgData *debug; static XYZMsgData *xyz; if(debug = dynamic_cast<DebugMsgData*>(msg->pdata)){ // debug message } else if(xyz = dynamic_cast<XYZMsgData*>(msg->pdata)){ // xyz message } else{ // ... } } 

const_cast:

 // *Passwd declared as a const const unsigned char *Passwd // on some situation it require to remove its constness const_cast<unsigned char*>(Passwd) 

reinterpret_cast:

 typedef unsigned short uint16; // Read Bytes returns that 2 bytes got read. bool ByteBuffer::ReadUInt16(uint16 val) { return ReadBytes(reinterpret_cast<char*>( 2); } 
165
21 янв. La respuesta la da Sumit Arora el 21 de enero. 2014-01-21 07:53 '14 a las 7:53 2014-01-21 07:53

Puede ayudar si conoces un poco de información interna.

static_cast

  • El compilador de C ++ ya sabe cómo convertir tipos de escala, como float, a int. Usa static_cast para ellos.
  • Cuando le pide al compilador que convierta el tipo A en B , static_cast llama al constructor B pasando A como parámetro. Alternativamente, A puede tener un operador de transformación (es decir, A::operator B() ). Si B no tiene tal constructor o A no tiene un operador de transformación, obtendrá un error en tiempo de compilación.
  • La conversión de A* a B* siempre B* exitosa si A y B están en la jerarquía de herencia (o nula), de lo contrario obtendrá un error de compilación.
  • Corrección : si coloca el puntero base al puntero derivado, pero si el objeto real no es realmente un tipo derivado, no obtendrá un error. Obtienes un puntero malo y lo más probable es un error de seguridad en el tiempo de ejecución. Lo mismo ocurre con A> B> .
  • Conseguido : ¡el reparto de Derivado a Base o viceversa creará una nueva copia! Para las personas que vienen de C # / Java, esto puede ser una gran sorpresa, porque el resultado es básicamente un objeto cortado creado a partir de Derivado.

dynamic_cast

  • dynamic_cast usa información de tipo de tiempo de ejecución para determinar si una conversión es válida. Por ejemplo, desde (Base*) a (Derived*) puede fallar si el puntero no es realmente un tipo derivado.
  • ¡Esto significa que dynamic_cast es muy caro en comparación con static_cast!
  • Para A* a B* , si la conversión es incorrecta, dynamic_cast devolverá nullptr.
  • Para A> to B> si la conversión es incorrecta, dynamic_cast lanzará una excepción bad_cast.
  • A diferencia de otros fantasmas, hay una sobrecarga de tiempo de ejecución.

const_cast

  • Mientras static_cast puede hacer constantes no constantes, no puede seguir una ruta diferente. Const_cast puede trabajar en ambas direcciones.
  • Un ejemplo donde esto es conveniente es iterar a través de un contenedor, por ejemplo, set<T> que solo devuelve sus elementos como const, para asegurarse de que no haya cambiado su clave. Sin embargo, si su intención es cambiar miembros no clave del objeto, entonces todo debería estar bien. Puedes usar const_cast para eliminar constness.
  • Otro ejemplo es cuando desea implementar T foo() así como const T foo() . Para evitar la duplicación de código, puede usar const_cast para devolver el valor de una función de otra.

reinterpretar_cast

  • Básicamente dice que toma estos bytes en esta ubicación de memoria y tómalo como un objeto dado.
  • Por ejemplo, puede cargar 4 bytes con un punto flotante a 4 bytes con un entero para ver cómo se ven los bits en un punto flotante.
  • Obviamente, si los datos no coinciden con el tipo, puede obtener una falta de seguridad.
  • No hay tiempo de sobrecarga para este tren.
65
11 дек. La respuesta es ShitalShah 11 de diciembre. 2016-12-11 05:05 '16 a las 5:05 a.m. 2016-12-11 05:05

¿Ayuda esto a responder tu pregunta?

Nunca he usado reinterpret_cast , y me pregunto si funciona en el caso de que lo necesite, no huele mal diseño. En el código base estoy trabajando en dynamic_cast . La diferencia con static_cast es que dynamic_cast realiza una verificación de tiempo de ejecución, que puede (más seguro) o no (más sobrecarga) ser lo que desea (ver msdn ).

12
01 дек. La respuesta se da andreas buykx 01 dic. 2008-12-01 23:20 '08 a las 11:20 2008-12-01 23:20

Además del resto de las respuestas, todavía hay un ejemplo no obvio donde static_cast no static_cast suficiente, por lo que se requiere un reinterpret_cast . Supongamos que hay una función que en el parámetro de salida devuelve los punteros a objetos de diferentes clases (que no tienen una clase base común). Un ejemplo real de dicha función es CoCreateInstance() (ver Último parámetro, que en realidad es void** ). Supongamos que está solicitando una clase de objeto particular de esta función, por lo que sabe de antemano el tipo de puntero (lo que a menudo hace para objetos COM). En este caso, no puede imponer un puntero a un puntero a void** utilizando static_cast : necesita reinterpret_cast<void**>(> .

En el código:

 #include <windows.h> #include <netfw.h> ..... INetFwPolicy2* pNetFwPolicy2 = nullptr; HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2), //static_cast<void**>( would give a compile error reinterpret_cast<void**>( ); 

Sin embargo, static_cast funciona para punteros simples (no punteros a punteros), por lo que el código anterior puede reescribirse para evitar reinterpret_cast (al precio de una variable adicional) de la siguiente manera:

 #include <windows.h> #include <netfw.h> ..... INetFwPolicy2* pNetFwPolicy2 = nullptr; void* tmp = nullptr; HRESULT hr = CoCreateInstance(__uuidof(NetFwPolicy2), nullptr, CLSCTX_INPROC_SERVER, __uuidof(INetFwPolicy2),  ); pNetFwPolicy2 = static_cast<INetFwPolicy2*>(tmp); 
12
31 мая '15 в 17:16 2015-05-31 17:16 La respuesta la da Serge Rogatch el 31 de mayo de 2015 a las 17:16 2015-05-31 17:16

Mientras que las otras respuestas describieron bien todas las diferencias entre las castas C ++, me gustaría agregar una breve nota de por qué no debería usar el tipo C (Type) var y el Type(var) .

Para los principiantes de C ++, el estilo C se parece a una operación de superconjunto en los modelos C ++ (static_cast <> (), dynamic_cast <> (), const_cast <> (), reinterpret_cast <> ()), y alguien puede preferirlos a C ++. De hecho, el estilo C es un superconjunto y más corto para escribir.

El principal problema de incorporar el estilo C es que ocultan la verdadera intención del desarrollador durante la creación. Los estilos de estilo C pueden realizar casi todos los tipos de conversión desde basura normalmente segura realizada por static_cast <> () y dynamic_cast <> () en roles potencialmente peligrosos, como const_cast <> (), donde el modificador de const puede eliminarse, por lo tanto constante las variables se pueden modificar y reinterpret_cast <> (), que incluso pueden reinterpretar los valores enteros a los punteros.

Aquí hay una muestra.

 int a=rand(); // Random number. int* pa1=reinterpret_cast<int*>(a); // OK. Here developer clearly expressed he wanted to do this potentially dangerous operation. int* pa2=static_cast<int*>(a); // Compiler error. int* pa3=dynamic_cast<int*>(a); // Compiler error. int* pa4=(int*) a; // OK. C-style cast can do such cast. The question is if it was intentional or developer just did some typo. *pa4=5; // Program crashes. 

La razón principal por la que se agregó C ++ al lenguaje fue para permitir que el desarrollador aclare sus intenciones, por qué lo va a hacer. Al usar conversiones de estilo C que son excelentes en C ++, hace que su código sea menos legible y más propenso a errores, especialmente para otros desarrolladores que no han creado su código. Por lo tanto, para hacer que su código sea más legible y explícito, siempre debe preferir C ++ a la conversión sobre estilos de C-style.

Aquí hay una breve cita de Bjarne Stroustrup (autor de C ++) del libro Lenguaje de programación C ++ de la 4ª edición - p. 302.

Este reparto de estilo C es mucho más peligroso que los operadores de transformación nombrados, porque escribir en un programa complejo es más complicado y el tipo de conversión para el programador no es explícito.

6
22 авг. La respuesta está dada por Timmy_A 22 ago. 2018-08-22 14:18 '18 a las 2:18 pm 2018-08-22 14:18

Para entender, veamos el siguiente fragmento de código:

 struct Foo{}; struct Bar{}; int main(int argc, char** argv) { Foo* f = new Foo; Bar* b1 = f; // (1) Bar* b2 = static_cast<Bar*>(f); // (2) Bar* b3 = dynamic_cast<Bar*>(f); // (3) Bar* b4 = reinterpret_cast<Bar*>(f); // (4) Bar* b5 = const_cast<Bar*>(f); // (5) return 0; } 

Sólo la línea (4) se compila sin errores. Solo reinterpret_cast puede usarse para convertir un puntero a un objeto en un puntero a cualquier tipo de objeto no relacionado.

Se debe tener en cuenta lo siguiente: dynamic_cast no funcionará en tiempo de ejecución, sin embargo, en la mayoría de los compiladores tampoco compilará, ya que la estructura del puntero que se está convirtiendo no tiene funciones virtuales, es decir, dynamic_cast solo funcionará con punteros de clase polimórficos.

Cuándo usar C ++ cast :

  • Use static_cast como el equivalente de una conversión de tipo C que convierte valores, o cuando necesitamos convertir explícitamente un puntero de una clase a su superclase.
  • Utilice const_cast para eliminar el calificador const.
  • Use reinterpret_cast para la conversión de tipo de puntero no seguro a entero y de otros tipos de punteros y viceversa. Use esto solo si sabemos lo que estamos haciendo y entendemos los problemas de los seudónimos.
0
21 дек. La respuesta es dada por Pankaj Kumar Thapa el 21 de diciembre. 2018-12-21 05:53 '18 a las 5:53 2018-12-21 05:53

Otras preguntas acerca de las etiquetas de ; o haga una pregunta