8.5 — Conversión explícita de tipos (casting) y static_cast

8.5 — Conversión explícita de tipos (casting) y static_cast

En la lección 8.1 -- Conversión implícita de tipos (coerción), discutimos que el compilador puede convertir implícitamente un valor de un tipo de datos a otro a través de un sistema llamado implicit type conversion . Cuando desea promocionar numéricamente un valor de un tipo de datos a un tipo de datos más amplio, está bien usar la conversión implícita de tipos.

Muchos programadores nuevos de C++ prueban algo como esto:

double d = 10 / 4; // does integer division, initializes d with value 2.0

Porque 10 y 4 ambos son del tipo int , se realiza la división de enteros y la expresión se evalúa como int valor 2 . Este valor luego se convierte en numérico a double valor 2.0 antes de usarse para inicializar la variable d . Lo más probable es que esto no sea lo que se pretendía.

En el caso de que esté utilizando operandos literales, reemplazar uno o ambos literales enteros con literales dobles hará que ocurra una división de punto flotante en su lugar:

double d = 10.0 / 4.0; // does floating point division, initializes d with value 2.5

Pero, ¿qué sucede si está utilizando variables en lugar de literales? Considere este caso:

int x { 10 };
int y { 4 };
double d = x / y; // does integer division, initializes d with value 2.0

Debido a que aquí se usa la división de enteros, la variable d terminará con el valor de 2.0 . ¿Cómo le decimos al compilador que queremos usar la división de punto flotante en lugar de la división de enteros en este caso? Los sufijos literales no se pueden usar con variables. Necesitamos alguna forma de convertir uno (o ambos) de los operandos variables a un tipo de coma flotante, de modo que en su lugar se use la división de coma flotante.

Afortunadamente, C++ viene con varios operadores de conversión de tipos diferentes (más comúnmente llamados conversiones) que el programador puede usar para solicitar que el compilador realice una conversión de tipos. Debido a que las conversiones son solicitudes explícitas del programador, esta forma de conversión de tipo a menudo se denomina conversión de tipo explícita (a diferencia de la conversión de tipo implícita, donde el compilador realiza una conversión de tipo automáticamente).

Tipo de fundición

C++ admite 5 tipos diferentes de conversiones:C-style casts , static casts , const casts , dynamic casts y reinterpret casts . Los últimos cuatro a veces se denominan elencos con nombre.

Cubriremos C-style casts y static casts en esta lección.

Contenido relacionado

Hablamos de las conversiones dinámicas en la lección 18.10 -- Casting dinámico, después de que hayamos cubierto otros temas de requisitos previos.

Const casts y reinterpret casts en general, deben evitarse porque solo son útiles en casos excepcionales y pueden ser dañinos si se usan incorrectamente.

Advertencia

Evite los moldes constantes y reinterprete los moldes a menos que tenga una muy buena razón para usarlos.

Moldes estilo C

En la programación C estándar, las conversiones se realizan a través del operador (), con el nombre del tipo para convertir el valor colocado entre paréntesis. Es posible que aún los veas utilizados en el código (o por programadores) que se han convertido de C.

Por ejemplo:

#include <iostream>

int main()
{
    int x { 10 };
    int y { 4 };

    
    double d { (double)x / y }; // convert x to a double so we get floating point division
    std::cout << d; // prints 2.5

    return 0;
}

En el programa anterior, usamos una conversión de estilo C para decirle al compilador que convierta x a un double . Debido a que el operando izquierdo de operator/ ahora se evalúa como un valor de coma flotante, el operando derecho también se convertirá a un valor de coma flotante, ¡y la división se realizará utilizando la división de coma flotante en lugar de la división de enteros!

C++ también te permitirá usar un C-style cast con una sintaxis más parecida a una llamada de función:

    double d { double(x) / y }; // convert x to a double so we get floating point division

Esto funciona de manera idéntica al ejemplo anterior, pero tiene la ventaja de poner entre paréntesis el valor que se está convirtiendo (lo que facilita saber qué se está convirtiendo).

Aunque un C-style cast parece ser un solo lanzamiento, en realidad puede realizar una variedad de conversiones diferentes según el contexto. Esto puede incluir un static cast , un const cast o un reinterpret cast (los dos últimos de los cuales mencionamos anteriormente debe evitar). Como resultado, C-style casts corren el riesgo de ser mal utilizados sin darse cuenta y no producir el comportamiento esperado, algo que se puede evitar fácilmente si se utilizan las conversiones de C++ en su lugar.

Contenido relacionado

Si tienes curiosidad, este artículo tiene más información sobre cómo funcionan realmente las conversiones de estilo C.

Mejores prácticas

Evite usar moldes de estilo C.

transmisión estática

C++ introduce un operador de conversión llamado static_cast, que se puede usar para convertir un valor de un tipo en un valor de otro tipo.

Has visto anteriormente static_cast usado para convertir un char en un int para que std::cout lo imprima como un número entero en lugar de un char :

#include <iostream>

int main()
{
    char c { 'a' };
    std::cout << c << ' ' << static_cast<int>(c) << '\n'; // prints a 97

    return 0;
}

El static_cast El operador toma una expresión como entrada y devuelve el valor evaluado convertido al tipo especificado dentro de los corchetes angulares. static_cast se utiliza mejor para convertir un tipo fundamental en otro.

#include <iostream>

int main()
{
    int x { 10 };
    int y { 4 };

    // static cast x to a double so we get floating point division
    double d { static_cast<double>(x) / y };  
    std::cout << d; // prints 2.5

    return 0;
}

La principal ventaja de static_cast es que proporciona verificación de tipos en tiempo de compilación, lo que dificulta cometer un error involuntario. static_cast también es (intencionalmente) menos potente que C-style casts , por lo que no puede eliminar sin darse cuenta const o hacer otras cosas que tal vez no tenía la intención de hacer.

Mejores prácticas

Favorezca static_cast cuando necesite convertir un valor de un tipo a otro tipo.

Uso de static_cast para hacer explícitas las conversiones de restricción

Los compiladores a menudo emiten advertencias cuando se realiza una conversión de tipo implícito potencialmente insegura (estrecha). Por ejemplo, considere el siguiente programa:

int i { 48 };
char ch = i; // implicit narrowing conversion

Emitir un int (2 o 4 bytes) a un char (1 byte) es potencialmente inseguro (ya que el compilador no puede saber si el valor entero desbordará el rango de char o no), por lo que el compilador normalmente imprimirá una advertencia. Si usáramos la inicialización de la lista, el compilador generaría un error.

Para evitar esto, podemos usar una conversión estática para convertir explícitamente nuestro número entero en un char :

int i { 48 };

// explicit conversion from int to char, so that a char is assigned to variable ch
char ch { static_cast<char>(i) };

Cuando hacemos esto, le estamos diciendo explícitamente al compilador que esta conversión está pensada y aceptamos la responsabilidad por las consecuencias (por ejemplo, desbordar el rango de un char si eso pasa). Desde la salida de este static_cast es de tipo char , la inicialización de la variable ch no genera ningún tipo de desajuste y, por lo tanto, no hay advertencias ni errores.

Aquí hay otro ejemplo en el que el compilador normalmente se quejará de que convertir un double a un int puede resultar en la pérdida de datos:

int i { 100 };
i = i / 2.5;

Para decirle al compilador que explícitamente queremos hacer esto:

int i { 100 };
i = static_cast<int>(i / 2.5);

Hora del examen

Pregunta #1

¿Cuál es la diferencia entre conversión de tipo implícita y explícita?

Mostrar solución

La conversión de tipos implícita se realiza automáticamente siempre que se espera un tipo de datos, pero se proporciona un tipo de datos diferente.
La conversión de tipos explícita ocurre cuando el programador usa una conversión de tipos para convertir explícitamente un valor de un tipo a otro tipo.