Curso de C++ v2.0
Consultas, lista de correo 'C++ Con Clase' 'C++ Con Clase' página de entrada Librerías estándar C Tabla de contenido Contactar con Webmaster
*Introducción
*1 Toma de contacto
*2 Variables I
*3 Funciones I: Declaración y definición
*4 Operadores I
*5 Sentencias
*6 Declaración de variables
*7 Normas para la notación
*8 Cadenas de caracteres
*9 Conversión de tipos
*10 Variables II: Arrays
*11 Variables III: Estructuras
*12 Variables IV: Punteros 1
*13 Operadores II: Más operadores
*14 Operadores III: Precedencia
*15 Funciones II: Parámetros por valor y referencia
*16 Variables V: Uniones
*17 Variables VI: Punteros 2
*18 Operadores IV: De bits y condicional
*19 Definición de tipos
*20 Funciones III
*21 Funciones IV: Sobrecarga
*22 Operadores V: Sobrecarga
*23 El preprocesador
*24 Funciones V: Recursividad
*25 Variables VII: Modificadores
*26 Espacios con nombre
*27 Clases I: Definiciones
*28 Declaración de clases
*29 Constructores
*30 Destructores
*31 El puntero this
*32 Sistema de protección
*33 Modificadores para miembros
*34 Más sobre funciones
*35 Operadores sobrecargados
 . Operadores binarios
 . El operador de asignación
 . Operadores sobrecargables
 . Forma funcional
 . Operadores en clases con punteros
 . Operadores unitarios
 . Unitarios sufijos
 . Unitarios sobrecargables
 . Conversión de tipo
 . Operador de indexación []
 . Operador de llamada ()
*36 Herencia
*37 Funciones virtuales
*38 Derivación múltiple
*39 Trabajar con ficheros
*40 Plantillas
*41 Punteros a miembros
*42 Castings
*43 Excepciones
*Ejemplos capítulos 1 a 6
*Ejemplos capítulos 8 y 9
*A Palabras reservadas C/C++
*B Trigrafos y símbolos alternativos
*C Librerías estándar
*D Streams
<< < > >>

Sobrecarga de operadores unitarios:  

Ahora le toca el turno a los operadores unitarios, que son aquellos que sólo requieren un operando, como la asignación o el incremento.

Cuando se sobrecargan operadores unitarios en una clase el operando es el propio objeto de la clase donde se define el operador. Por lo tanto los operadores unitarios dentro de las clases no requieren operandos.

Sintaxis:

<tipo> operator<operador unitario>();

Normalmente el <tipo> es la clase para la que estamos sobrecargando el operador. Sigamos con el ejemplo de la clase para el tratamiento de tiempos, sobrecargaremos ahora el operador de incremento ++:

class Tiempo {
...
Tiempo operator++();
...
};
 
Tiempo Tiempo::operator++() {
   minuto++;
   while(minuto >= 60) {
      minuto -= 60;
      hora++;
   }
   return *this;
}
...
 
T1.Mostrar();
++T1;
T1.Mostrar();
...

Operadores unitarios sufijos:  

Lo que hemos visto vale para el preincremento, pero, ¿cómo se sobrecarga el operador de postincremento?

En realidad no hay forma de decirle al compilador cuál de las dos modalidades del operador estamos sobrecargando, así que los compiladores usan una regla: si se declara un parámetro para un operador ++ ó -- se sobrecargará la forma sufija del operador. El parámetro se ignorará, así que bastará con indicar el tipo.

También tenemos que tener en cuenta el peculiar funcionamiento de los operadores sufijos, cuando los sobrecarguemos, al menos si queremos mantener el comportamiento que tienen normalmente.

Cuando se usa un operador en la forma sufijo dentro de una expresión, primero se usa el valor actual del objeto, y una vez evaluada la expresión, se aplica el operador. Si nosotros queremos que nuestro operador actúe igual deberemos usar un objeto temporal, y asignarle el valor actual del objeto. Seguidamente aplicamos el operador al objeto actual y finalmente retornamos el objeto temporal.

Veamos un ejemplo:

class Tiempo {
...
Tiempo operator++();    // Forma prefija
Tiempo operator++(int); // Forma sufija
...
};
 
Tiempo Tiempo::operator++() {
   minuto++;
   while(minuto >= 60) {
      minuto -= 60;
      hora++;
   }
   return *this;
}
 
Tiempo Tiempo::operator++(int) {
   Tiempo temp(*this); // Constructor copia
 
   minuto++;
   while(minuto >= 60) {
      minuto -= 60;
      hora++;
   }
   return temp;
}
...
 
// Prueba:
T1.Mostrar();
(T1++).Mostrar();
T1.Mostrar();
(++T1).Mostrar();
T1.Mostrar();
...

Salida:

17:9 (Valor inicial)
17:9 (Operador sufijo, el valor no cambia 
      hasta después de mostrar el valor)
17:10 (Resultado de aplicar el operador)
17:11 (Operador prefijo, el valor cambia 
       antes de mostrar el valor)
17:11 (Resultado de aplicar el operador)

Operadores unitarios que pueden sobrecargarse:  

Además del operador ++ y -- pueden sobrecargarse prácticamente todos los operadores unitarios:

+, -, ++, --, *, & y !.

Operadores de conversión de tipo:  

Volvamos a nuestra clase Tiempo. Imaginemos que queremos hacer una operación como la siguiente:

Tiempo T1(12,23);
unsigned int minutos = 432;
 
T1 += minutos;

Con toda probabilidad no obtendremos el valor deseado.

Como ya hemos visto, en C++ se realizan conversiones implícitas entre los tipos básicos antes de operar con ellos, por ejemplo para sumar un int y un float, se convierte el entero a float. Esto se hace también en nuestro caso, pero no como esperamos.

El valor "minutos" se convierte a un objeto Tiempo, usando el constructor que hemos diseñado. Como sólo hay un parámetro, el parámetro m toma el valor 0, y para el parámetro h se convierte el valor "minutos" de unsigned int a int.

El resultado es que se suman 432 horas, y nosotros queremos sumar 432 minutos.

Esto se soluciona creando un nuevo constructor que tome como parámetro un unsigned int.

Tiempo(unsigned int m) : hora(0), minuto(m) {
   while(minuto >= 60) {
      minuto -= 60;
      hora++;
   }
}

Ahora el resultado será el adecuado.

En general podremos hacer conversiones de tipo desde cualquier objeto a un objeto de nuestra clase sobrecargando el constructor.

Pero también se puede presentar el caso contrario. Ahora queremos asignar a un entero un objeto Tiempo:

Tiempo T1(12,23);
int minutos;
 
minutos = T1;

En este caso obtendremos un error de compilación, ya que el compilador no sabe convertir un objeto Tiempo a entero.

Para eso tenemos que diseñar nuestro operador de conversión de tipo, que se aplicará automáticamente.

Los operadores de conversión de tipos tienen el siguiente formato:

operator <tipo>();

No necesitan que se especifique el tipo del valor de retorno, ya que este es precisamente <tipo>. Además, al ser operadores unitarios, tampoco requieren argumentos, se aplican al propio objeto.

class Tiempo {
...
operator int(); 
...
 
operator int() {
   return hora*60+minuto;
}

Por supuesto, el tipo no tiene por qué ser un tipo básico, puede tratarse de una estructura o una clase.

<< < > >>