sábado, 16 de agosto de 2014

C++, conversión explícita o cast

Cuando necesitamos convertir una variable perteneciente a un tipo de dato (cadena, numérico, fecha, etc.) a otro tipo diferente del suyo original, debemos decirle al programa explícitamente que tipo de conversión deseamos.

La conversión explícita en vez de realizarla el compilador automáticamente se indica de forma explícita, en C++ utilizamos la forma (nombre_de_tipo)expresión.  No es exclusiva de C++ pues también se puede emplear en otros programas aunque cambie ligeramente la implementación.

Conversión explícita Cast

Notación cast

Si tenemos una función previamente definida que espera un tipo determinado, por ejemplo la función raíz cuadrada  (sqrt) espera como argumento un tipo double, para evitar una salida inesperada en el caso de pasar un argumento de otro tipo, podemos escribir:
sqrt ( ( double ) ( n + 2) );
De este modo forzamos para que el resultado de ( n + 2 ) sea siempre un tipo double y se lo pase a la función sqrt.

En C++  es posible expresar también una construcción cast de la forma siguiente: nombre_de_tipo(expresión) esta recibe el nombre de notación funcional,  y no se puede utilizar con tipos que tengan un nombre simple.

Notación funcional

Para convertir un valor a un tipo puntero utilizando la notación cast escribiríamos:
int *p =  ( int *)0x1F5;
Pero utilizando la notación funcional escribiremo:
typedef int *pint;
int *p = pint(0x1F5);

Una variable de un determinado tipo no siempre puede ser convertida explícitamente a otro tipo.  En este caso:
struct
      {
unsigned int a : 3;   // bits 0 a 2
unsigned int b : 1;   // bit 3
unsigned int c : 3;   // bits 4 a 6
unsigned int d : 1;  // bit 7
       } atributo;

La variable atributo tiene una longitud de ocho bits. Pero si intentamnos copiar la variable atributo a una variable atrib de tipo char  y escribimos.
char atrib = char atributo;  // error

Da un error, ya que C++ no permite convertir una estructura a un tipo como char aunque las longitudes de ambos sean iguales.

Conversión de Punteros

Utilizando conversiones explícitas de tipo sobre punteros, es posible convertir el valor de una variable de un determinado tipo a otro cualquiera. El formato general para hacer esto es: cualquier_tipo *p = ( cualquier_tipo *)&variable. Aplicando esto al caso anterior, obtendríamos:
char * atrib = ( char *)&atributo;
Con lo que char a = * atrib; define la variable a de tipo char, cuyo contenido es el mismo que el de la estructura atributo.

Constructores y operadores de conversión

Cuando trabajamos con clases, nosotros mismos tenemos que construir las conversiones que deseamos que realice el compilador cuando utilice un objeto de una clase. Estas conversiones pueden ser o entre una clase y un tipo predefinido. Para ello podemos utilizar dos mecanismos; constructores y operadores de conversión.

Constructores

Podemos definir una conversión a través de un constructor que tome un argumento de un determinado tipo como entrada y lo convierta en un objeto de una determinada clase.
En la definición de una clase podemos definir el siguiente constructor:
nombre_de_clase (int r)
{
real = ( double )r; imag = 0;
}
Que sirve para construir un número complejo.
Este constructor además de inicializar un objeto complejo utilizando solamente un valor también permite asignar directamente un entero int a un objeto complejo como se muestra a continuación.
complejo c(3);  // construye el complejo (3,0)
c = 6;          // equivale a c = complejo(6)

Operador de conversión

Ahora se desea que se realice  también de una forma implícita o explícita, si existe ambigüedad, la conversión de un tipo definido por el usuario a un tipo básico:
double d;
CRacional r(1,2);
d = r ;  // r tiene que convertirse a double

para que la instrucción d = r se ejecute correctamente, es necesario realizar una conversión implícita de CRacional a double. Este tipo de conversión no está permitido con un constructor, ya que no podemos definir un constructor de un tipo base.
Cuando necesitamos convertir objetos de un tipo de clase a otro tipo, tenemos que utilizar un operador de conversión. La sintaxis para este operador es:
C::operator T();
Donde T es el nombre de un tipo. La conversión que se realiza es de C a T.
Para convertir de CRacional a double.
class CRacional
{
//.......
operador double();
};
inline CRacional::operator double()
{
return ( double )numerador/( double )denominador;
}
Un operador de conversión no puede tener argumentos ni tipo del valor que se retorna.
Un operador de conversión se puede llamar de a través de las formas siguientes:
double d;
CRacional r(1,2);
d = r.operator double();/llamada explícita a la función
d = double(r);//conversión explícita (notación funcional )
d = ( double )r; //conversión explícita cast
d = r ;  // conversión implícita

Un operador de conversión puede llamarse explícitamente pero su principal utilidad es que sea llamado automáticamente por el compilador cuando la evaluación de una expresión requiere el tipo de conversión realizado por él.
También puede definirse un operador de conversión que convierta un objeto de una clase a otro objeto de otra clase.

Conversión del tipo void*


El tipo void se puede utilizar para definir un puntero a un elemento genérico. Como podemos ver la función C malloc se define como:
void *malloc(size_t n);

En C, la conversión del  tipo void* a otro tipo podía realizarse de forma  implícita de este modo.
char *p = malloc(longitud + 1);
Pero en C++ esta conversión tiene que realizarse de forma explícita. Esto es.
char *p = ( char * ) malloc ( longitud + 1 );

No hay comentarios:

Publicar un comentario