Saltar al contenido

Reparto normal vs.estático_cast vs.Dinámico_cast

Solución:

static_cast

static_cast se utiliza para los casos en los que básicamente desea revertir una conversión implícita, con algunas restricciones y adiciones. static_cast no realiza comprobaciones en tiempo de ejecución. Esto debe usarse si sabe que se refiere a un objeto de un tipo específico y, por lo tanto, una verificación no sería necesaria. Ejemplo:

void func(void *data) {
  // Conversion from MyClass* -> void* is implicit
  MyClass *c = static_cast<MyClass*>(data);
  ...
}

int main() {
  MyClass c;
  start_thread(&func, &c)  // func(&c) will be called
      .join();
}

En este ejemplo, sabe que pasó un MyClass object y, por lo tanto, no es necesario realizar una verificación de tiempo de ejecución para garantizar esto.

transmisión_dinámica

dynamic_cast es útil cuando no se sabe cuál es el tipo dinámico del objeto. Devuelve un puntero nulo si el objeto al que se hace referencia no contiene el tipo convertido como clase base (cuando se lanza a una referencia, un bad_cast se lanza una excepción en ese caso).

if (JumpStm *j = dynamic_cast<JumpStm*>(&stm)) {
  ...
} else if (ExprStm *e = dynamic_cast<ExprStm*>(&stm)) {
  ...
}

No se puede utilizar dynamic_cast si abatiste (lanza a una clase derivada) y el tipo de argumento no es polimórfico. Por ejemplo, el siguiente código no es válido porque Base no contiene ninguna función virtual:

struct Base { };
struct Derived : Base { };
int main() {
  Derived d; Base *b = &d;
  dynamic_cast<Derived*>(b); // Invalid
}

Un “up-cast” (lanzado a la clase base) siempre es válido con ambos static_cast y dynamic_cast, y también sin ningún elenco, ya que un “up-cast” es una conversión implícita.

Reparto regular

Estos yesos también se denominan yesos estilo C. Un elenco de estilo C es básicamente idéntico a probar una variedad de secuencias de elencos de C ++ y tomar el primer elenco de C ++ que funcione, sin siquiera considerar dynamic_cast. No hace falta decir que esto es mucho más poderoso ya que combina todos los const_cast, static_cast y reinterpret_cast, pero también es inseguro, porque no usa dynamic_cast.

Además, los lanzamientos de estilo C no solo te permiten hacer esto, sino que también te permiten lanzar de forma segura a una clase base privada, mientras que el “equivalente” static_cast La secuencia le daría un error en tiempo de compilación para eso.

Algunas personas prefieren los yesos estilo C debido a su brevedad. Los uso solo para conversiones numéricas, y uso las conversiones de C ++ apropiadas cuando están involucrados los tipos definidos por el usuario, ya que proporcionan una verificación más estricta.

Reparto estático

La transmisión estática 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 memoria asignada, escribir en este puntero causará un error de tiempo de ejecución o sobrescribirá parte de la memoria adyacente.

*p = 5; // run-time error: stack corruption

A diferencia de la conversión de estilo C, la conversión estática permitirá al compilador comprobar que los tipos de datos de puntero y puntero 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

Reinterpretar reparto

Para forzar la conversión del puntero, de la misma manera que lo hace la conversión de estilo C en el fondo, se usaría la conversión de reinterpretación.

int *r = reinterpret_cast<int*>(&c); // forced conversion

Esta conversión maneja conversiones entre ciertos tipos no relacionados, como de un tipo de puntero a otro tipo de puntero incompatible. Simplemente realizará una copia binaria de los datos sin alterar el patrón de bits subyacente. Tenga en cuenta que el resultado de una operación de tan bajo nivel es específico del sistema y, por lo tanto, no es portátil. Debe usarse con precaución si no se puede evitar por completo.

Reparto dinámico

Este solo se usa para convertir punteros a objetos y referencias a objetos en otros tipos de punteros o referencias en la jerarquía de herencia. Es la única conversión que se asegura de que el objeto al que se apunta se pueda convertir, realizando una verificación en tiempo de ejecución de que el puntero se refiere a un objeto completo del tipo de destino. Para que esta verificación en tiempo de ejecución sea posible, el objeto debe ser polimórfico. Es decir, la clase debe definir o heredar al menos una función virtual. Esto se debe a que el compilador solo generará la información de tipo en tiempo de ejecución necesaria para dichos objetos.

Ejemplos de reparto dinámico

En el siguiente ejemplo, un puntero MyChild se convierte en un puntero MyBase mediante una conversión dinámica. Esta conversión de derivado a base se realiza correctamente porque el objeto Child incluye un objeto Base completo.

class MyBase 
{ 
  public:
  virtual void test() {}
};
class MyChild : public MyBase {};



int main()
{
  MyChild *child = new MyChild();
  MyBase  *base = dynamic_cast<MyBase*>(child); // ok
}

El siguiente ejemplo intenta convertir un puntero MyBase en un puntero MyChild. Dado que el objeto Base no contiene un objeto Child completo, esta conversión de puntero fallará. Para indicar esto, la transmisión dinámica devuelve un puntero nulo. Esto proporciona una forma conveniente de comprobar si una conversión se ha realizado correctamente durante el tiempo de ejecución.

MyBase  *base = new MyBase();
MyChild *child = dynamic_cast<MyChild*>(base);

 
if (child == 0) 
std::cout << "Null pointer returned";

Si se convierte una referencia en lugar de un puntero, la conversión dinámica fallará al lanzar una excepción bad_cast. Esto debe manejarse mediante una declaración try-catch.

#include <exception>
// …  
try
{ 
  MyChild &child = dynamic_cast<MyChild&>(*base);
}
catch(std::bad_cast &e) 
{ 
  std::cout << e.what(); // bad dynamic_cast
}

Reparto dinámico o estático

La ventaja de utilizar una conversión dinámica es que permite al programador comprobar si una conversión se ha realizado correctamente durante el tiempo de ejecución. La desventaja es que hay una sobrecarga de rendimiento asociada con la realización de esta verificación. Por esta razón, habría sido preferible utilizar una conversión estática en el primer ejemplo, porque una conversión derivada a base nunca fallará.

MyBase *base = static_cast<MyBase*>(child); // ok

Sin embargo, en el segundo ejemplo, la conversión puede tener éxito o fallar. Fallará si el objeto MyBase contiene una instancia MyBase y tendrá éxito si contiene una instancia MyChild. En algunas situaciones, es posible que esto no se sepa hasta el momento de la ejecución. Cuando este es el caso, el reparto dinámico es una mejor opción que el reparto estático.

// Succeeds for a MyChild object
MyChild *child = dynamic_cast<MyChild*>(base);

Si la conversión de base a derivada se hubiera realizado utilizando una conversión estática en lugar de una conversión dinámica, la conversión no habría fallado. Habría devuelto un puntero que se refería a un objeto incompleto. Desreferenciar un puntero de este tipo puede provocar errores en tiempo de ejecución.

// Allowed, but invalid
MyChild *child = static_cast<MyChild*>(base);
 
// Incomplete MyChild object dereferenced
(*child);

Reparto constante

Este se usa principalmente para agregar o eliminar el modificador const de una variable.

const int myConst = 5;
int *nonConst = const_cast<int*>(&myConst); // removes const

Aunque const cast permite cambiar el valor de una constante, hacerlo sigue siendo un código no válido que puede provocar un error en tiempo de ejecución. Esto podría ocurrir, por ejemplo, si la constante estuviera ubicada en una sección de la memoria de solo lectura.

*nonConst = 10; // potential run-time error

En cambio, la conversión constante se usa principalmente cuando hay una función que toma un argumento de puntero no constante, aunque no modifica el puntero.

void print(int *p) 
{
   std::cout << *p;
}

A continuación, se puede pasar a la función una variable constante mediante el uso de una conversión constante.

print(&myConst); // error: cannot convert 
                 // const int* to int*
 
print(nonConst); // allowed

Fuente y más explicaciones

Deberías mirar el artículo Programación C ++ / Conversión de tipos.

Contiene una buena descripción de todos los diferentes tipos de elenco. Lo siguiente tomado del enlace anterior:

const_cast

const_cast (expresión) El const_cast <> () se usa para agregar / eliminar const (ness) (o volatile-ness) de una variable.

static_cast

static_cast (expresión) El static_cast <> () se usa para lanzar entre los tipos enteros. ‘eg’ char-> long, int-> short etc.

La conversión estática también se usa para lanzar punteros a tipos relacionados, por ejemplo, lanzar void * al tipo apropiado.

transmisión_dinámica

La conversión dinámica se utiliza para convertir punteros y referencias en tiempo de ejecución, generalmente con el propósito de convertir un puntero o referencia hacia arriba o hacia abajo en una cadena de herencia (jerarquía de herencia).

dynamic_cast (expresión)

El tipo de destino debe ser un puntero o un tipo de referencia, y la expresión debe evaluarse como un puntero o una referencia. La conversión dinámica funciona solo cuando el tipo de objeto al que se refiere la expresión es compatible con el tipo de destino y la clase base tiene al menos una función de miembro virtual. Si no es así, y el tipo de expresión que se está convirtiendo es un puntero, se devuelve NULL; si falla una conversión dinámica en una referencia, se lanza una excepción bad_cast. Cuando no falla, la conversión dinámica devuelve un puntero o referencia del tipo de destino al objeto al que se refiere la expresión.

reinterpret_cast

Reinterpret cast simplemente lanza un tipo bit a bit a otro. Cualquier puntero o tipo integral se puede convertir en cualquier otro con una reinterpretación, lo que permite un uso indebido fácilmente. Por ejemplo, con reinterpretar la conversión, uno podría, de manera insegura, lanzar un puntero entero a un puntero de cadena.

¡Haz clic para puntuar esta entrada!
(Votos: 1 Promedio: 4)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *