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.
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