Inicia sesión


Curso De C++ - Capitulo 35

Operadores sobrecargados

Ya habíamos visto el funcionamiento de los operadores sobrecargados en el capítulo 22, aplicándolos a operaciones con estructuras. Ahora veremos todo su potencial, aplicándolos a clases.

 
Sobrecarga de operadores binarios

Empezaremos por los operadores binarios, que como recordarás son aquellos que requieren dos operandos, como la suma o la resta.

Existe una diferencia entre la sobrecarga de operadores que vimos en el capítulo 22, que se definía fuera de las clases. Cuando se sobrecargan operadores en el interior se asume que el primer operando es el propio objeto de la clase donde se define el operador. Debido a esto, sólo se necesita especificar un operando.
Sintaxis:
<tipo> operator<operador binario>(<tipo> <identificador>); 
Normalmente el <tipo> es la clase para la que estamos sobrecargando el operador, tanto en el valor de retorno como en el parámetro.

Veamos un ejemplo para una clase para el tratamiento de tiempos:
#include <iostream>
using namespace std;
 
class Tiempo {
  public:
   Tiempo(int h=0, int m=0) : hora(h), minuto(m) {}
   
   void Mostrar();
   Tiempo operator+(Tiempo h);
       
  private:
   int hora;
   int minuto;
};

Tiempo Tiempo::operator+(Tiempo h) {
   Tiempo temp;
   
   temp.minuto = minuto + h.minuto;
   temp.hora   = hora   + h.hora;
   
   if(temp.minuto >= 60) {
      temp.minuto -= 60;
      temp.hora++;
   }
   return temp;
}

void Tiempo::Mostrar() {
   cout << hora << ":" << minuto << endl;
}

int main() {
   Tiempo Ahora(12,24), T1(4,45);
   
   T1 = Ahora + T1;   // (1)
   T1.Mostrar();
   
   (Ahora + Tiempo(4,45)).Mostrar(); // (2)
   
   return 0;
} 
Me gustaría hacer algunos comentarios sobre el ejemplo:

Observa que cuando sumamos dos tiempos obtenemos un tiempo, se trata de una propiedad de la suma, todos sabemos que no se pueden sumar peras y manzanas.

Pero en C++ sí se puede. Por ejemplo, podríamos haber sobrecargado el operador suma de este modo:
int operator+(Tiempo h);

Pero no estaría muy clara la naturaleza del resultado, ¿verdad?. Lo lógico es que la suma de dos objetos produzca un objeto del mismo tipo o la misma clase.

Hemos usado un objeto temporal para calcular el resultado de la suma, esto es necesario porque necesitamos operar con los minutos para prevenir el caso en que excedan de 60, en cuyo caso incrementaremos el tiempo en una hora.

Ahora observa cómo utilizamos el operador en el programa.
La forma (1) es la forma más lógica, para eso hemos creado un operador, para usarlo igual que en las situaciones anteriores.

Pero verás que también hemos usado el operador =, a pesar de que nosotros no lo hemos definido. Esto es porque el compilador crea un operador de asignación por defecto si nosotros no lo hacemos, pero veremos más sobre eso en el siguiente punto.

La forma (2) es una pequeña aberración, pero ilustra cómo es posible crear objetos temporales sin nombre.

En esta línea hay dos, el primero Tiempo(4,45), que se suma a Ahora para producir otro objeto temporal sin nombre, que es el que mostramos en pantalla.

Sobrecargar el operador de asignación: ¿por qué?

Ya sabemos que el compilador crea un operador de asignación por defecto si nosotros no lo hacemos, así que ¿por qué sobrecargarlo?

Bueno, veamos lo que pasa si nuestra clase tiene miembros que son punteros, por ejemplo:
class Cadena {
  public:
   Cadena(char *cad);
   Cadena() : cadena(NULL) {};
   ~Cadena() { delete[] cadena; };
   
   void Mostrar() const;
  private:
   char *cadena;
};
  
Cadena::Cadena(char *cad) {
   cadena = new char[strlen(cad)+1];
   strcpy(cadena, cad);
}
 
void Cadena::Mostrar() const {
   cout << cadena << endl;
} 
Si en nuestro programa declaramos dos objetos de tipo Cadena:
Cadena C1("Cadena de prueba"), C2;
Y hacemos una asignación:
C2 = C1;
Lo que realmente copiamos no es la cadena, sino el puntero. Ahora los dos punteros de las cadenas C1 y C2 están apuntando a la misma dirección. ¿Qué pasará cuando destruyamos los objetos? Al destruir C1 se intentará liberar la memoria de su puntero cadena, y al destruir C2 también, pero ambos punteros apuntan a la misma dirección y el valor original del puntero de C2 se ha perdido, por lo que su memoria no puede ser liberada.

En estos casos, análogamente a lo que sucedía con el constructor copia, deberemos sobrecargar el operador de asignación. En nuestro ejemplo podría ser así:
Cadena &Cadena::operator=(const Cadena &c) {
   if(this != &c) {
      delete[] cadena;
      if(c.cadena) {
         cadena = new char[strlen(c.cadena)+1];
         strcpy(cadena, c.cadena);
      }
      else cadena = NULL;
   }
   return *this;
} 
Hay que tener en cuenta la posibilidad de que se asigne un objeto a si mismo. Por eso comparamos el puntero this con la dirección del parámetro, si son iguales es que se trata del mismo objeto, y no debemos hacer nada. Esta es una de las situaciones en las que el puntero this es imprescindible.
También hay que tener cuidado de que la cadena a copiar no sea NULL, en ese caso no debemos copiar la cadena, sino sólo asignar NULL a cadena.

Y por último, también es necesario retornar una referencia al objeto, esto nos permitirá escribir expresiones como estas:
 
C1 = C2 = C3;
if((C1 = C2) == C3)...
 
Por supuesto, para el segundo caso deberemos sobrecargar también el operador ==.
Continuar Con El Capitulo 35  | Ir al Principio


  • Autor:
  • Editor: Tutoriales En Linea
  • Fecha:2015-05-25
  • Categorias: Noticias Tutorial Tutorial C++




Información
Usuarios que no esten registrados no pueden dejar comentarios, te invitamos a que te registre!






Efectos jQuery - Ocultar y mostrar

  • Autor:
  • Editor: Tutoriales En Linea
  • Fecha:2019-11-17
  • Categorias: Diseño Web Lenguajes De Programacion html5 jQuery WebSite webmasters Noticias Tutorial

Como abrir un enlace con jQuery

  • Autor:
  • Editor: Tutoriales En Linea
  • Fecha:2019-11-17
  • Categorias: Diseño Web Lenguajes De Programacion html5 jQuery WebSite webmasters Noticias Tutorial

Cómo rastrear a los usuarios de Adblock usando Google Analytics

  • Autor:
  • Editor: Tutoriales En Linea
  • Fecha:2019-11-15
  • Categorias: Google WebSite Trucos y tips Noticias Tutorial

Curso de iniciación de JavaScript

  • Autor:
  • Editor: Tutoriales En Linea
  • Fecha:2019-10-21
  • Categorias: Lenguajes De Programacion javascript Cursos Noticias Tutorial

Cómo insertar código JavaScript

  • Autor:
  • Editor: Tutoriales En Linea
  • Fecha:2019-10-21
  • Categorias: Lenguajes De Programacion javascript Cursos Noticias Tutorial

Expresiones JavaScript para especificar valores de atributos en HTML

  • Autor:
  • Editor: Tutoriales En Linea
  • Fecha:2019-10-21
  • Categorias: Lenguajes De Programacion javascript Cursos Noticias Tutorial