Casting. Conversión entre tipos de datos en C++

Cuando en una expresión en C++ intervienen operandos de distinto tipo, los datos se convierten de forma temporal al operando de mayor precisión para realizar la operación.
Cuando a un variable se le asigna un valor que no es de su tipo, C++ convierte el valor de la derecha al tipo de la variable a la que se le va a asignar siempre que no haya pérdida de información.
Si se produce pérdida de información el compilador avisará de ello.
En una asignación de tipos distintos puede ocurrir que:
1. Un valor real (tipo double o float) puede truncarse (pierde la parte decimal) si se asigna a una variable entera.

2. Un valor de tipo double puede ser redondeado si se asigna a una variable de tipo float.

3. Un valor de tipo entero puede ser modificado si se asigna a una variable entera de menor precisión o a una variable de tipo char. Algunos de los bits más significativos pueden perderse.


Por ejemplo, dadas las siguientes declaraciones de variables:
long int k;
unsigned char m;
double p;
int n, q;
Para calcular la siguiente expresión: q = k + m * n / p    el proceso es el siguiente:
1. Se realiza la multiplicación m * n. Para ello se convierte m (unsigned char) a int y a continuación se multiplica por n. El resultado es de tipo int.
2. Se realiza la división. Como p es de tipo double, el resultado anterior de multiplicar m * n que es de tipo int se convierte a double y se hace la división. El resultado es de tipo double.
3. Se realiza la suma. Para ello se convierte k (long) a double y se suma al resultado de la división anterior. El resultado de la suma es de tipo double.
4. El último paso es asignar el resultado de tipo double a q que es de tipo int. En este caso el resultado se pasa a tipo int por truncamiento, o sea, eliminando la parte fraccionaria. En este caso de pérdida de precisión el compilador avisará de ello.
Estas conversiones las realiza C++ de forma automática. Esta conversión se conoce como conversión implícita.
En algunos casos necesitaremos asignar datos de un tipo a variables que son de otro tipo y que el compilador no nos avise ello y permita realizar la operación. En ese caso utilizaremos la conversión explícita o casting.
En general, el uso del casting es obligatorio cuando se hacen asignaciones con pérdida de precisión.
Un casting lo podemos hacer, siguiendo el modelo de C, de dos formas:
(tipo) expresión 
ó
tipo(expresión)
Por ejemplo:
float a = 10.2;
int b, c = 5;
b = (int)(a + c);  // convierte a int por truncamiento. Asigna a b el valor 15
c = int (a);         // asigna a c el valor 10
Si en las instrucciones anteriores no realizamos el casting el compilador avisará de la pérdida de precisión y no nos dejará hacerlo.

Otro ejemplo. Dadas las variables: 
int i = 7;
float f = 8.5;
La expresión (i + f) % 4 no es válida, ya que (i + f) produce un resultado en coma flotante.
Esto se puede solucionar con un casting:
((int) (i + f)) % 4.
Sea ahora la expresión ((int) f) % 3, es una expresión válida, que da como resultado el valor 2, pero debemos tener en cuenta que lo que se convierte en entero es el valor de f, y sólo para esta expresión, ya que después f  sigue teniendo el valor 8.5.
Un casting también puede ser considerado como un operador unitario.
Además de esta forma de realizar un casting que es la tradicional de C, C++ incorpora 4 nuevos operadores para realizar un casting de forma explícita:
static_cast<tipo>(expresión)
Convierte el tipo de la expresión al tipo indicado.
Se utiliza para realizar conversiones entre tipos relacionados, por ejemplo entre un float y un int.
const_cast<tipo>(expresión)  
Convierte el tipo de la expresión al tipo indicado.
Se utiliza para eliminar la acción del calificador const sobre la expresión.
dynamic_cast<tipo>(expresión)  
Convierte el tipo de la expresión al tipo indicado.
Se utiliza para realizar conversiones verificadas durante la ejecución, examinando el tipo del objeto que convierte.
Si la conversión es entre punteros y durante la ejecución no se puede realizar, devuelve un cero (puntero nulo).
reinterpret_cast<tipo>(expresión)
Convierte el tipo de la expresión al tipo indicado.
Se utiliza para realizar conversiones entre tipos no relacionados, por ejemplo, conversiones double * a int * que static_cast no permite.
Por ejemplo:
float a = 10.2F;
int b, c = 5;
b = static_cast<int>(a + c); // Asigna a b el valor 15
c = static_cast<int>(a);       // asigna a c el valor 10


5 comentarios:

  1. entonces cual es la firencia entre "(int)" con un "static_cast", para que en c++ se hace otro, que hace lo mismo que el primero???, gracias por el aporte de antemano.

    ResponderEliminar
  2. El casting c++ introduce seguridad en la conversión. El casting estilo C te deja hacer casi cualquier cosa y realizar conversiones entre tipos no relacionados sin ningún tipo de aviso. El casting c++ entre tipos no relacionados lo debes indicar expresamente, asegurándote de esa forma que es eso lo que realmente quieres hacer.
    Por ejemplo:

    float a = 123.456;
    char *c = (char*)&a; //compila perfectamente
    char *d = static_cast<char *>(&a); //error de compilación al intentar convertir un float* a un char*

    Para hacer esta operación tenemos que escribir:
    char *d = reinterpret_cast<char *>(&a);
    Con esto estamos indicando que realmente es esa la operación que queremos hacer

    ResponderEliminar
    Respuestas
    1. Buen aporte, la aclaracion, me ha ayudado

      Eliminar
  3. Hola Enrique, qué debo de entender por Tipo de Datos Relacionados y No Relacionados ?
    Gracias de antemano.
    Saludes

    ResponderEliminar