6.- SOBRECARGA DE FUNCIONES Y OPERADORES

 C++ proporciona las herramientas necesarias que permiten definir funciones y operadores que utilizan el mismo nombre o símbolo que una función u operador incorporado. Estas funciones y operadores se dicen que están sobrecargados y se pueden utilizar para redefinir una función u operador definido.

6.1 Sobrecarga de funciones

En C++ dos o más funciones pueden tener el mismo nombre representando cada una de ellas un código diferente. Esta característica se conoce como sobrecarga de funciones.
Una función sobrecargada es una función que tiene más de una definición.
Estas funciones se diferencian en el número y tipo de argumentos, pero también hay funciones sobrecargadas que devuelven tipos distintos.
Sobrecarga se refiere al uso de un mismo nombre para múltiples significados de un operador o una función.
Dado el énfasis del concepto de clase, el uso principal de la sobrecarga es con las funciones miembro de una clase. Cuando más de una función miembro con igual nombre se declara en una clase, se dice que el nombre de la función está sobrecargado en esa clase. El ámbito del nombre sobrecargado es el de la clase.
La sobrecarga de funciones amigas es similar a la de funciones miembro, con la única diferencia de que es necesaria la palabra reservada friend al igual que en la declaración de cualquier función amiga.

6.2 Sobrecarga de operadores

De modo análogo a la sobrecarga de funciones, la sobrecarga de operadores permite al programador dar nuevos significados a los símbolos de los operadores existentes en C++.
C++ permite a los programadores sobrecargar a los operadores para tipos abstractos de datos.
Operadores que se pueden sobrecargar:

+

-

*

/

%

^

&

|

_

'

=

<

>

<=

>=

++

--

<<

>>

==

0

%%

||

+=

-=

*=

/=

%=

&=

|=

<<=

>>=

[ ]

( )

->

->*

new

delete

 

 

Si un operador tiene formatos unitarios y binarios (tales como + y &) ambos formatos pueden ser sobrecargados. Un operador unitario tiene un parámetro, mientras que un operador binario tiene dos. El único operador ternario, ?:, no se puede sobrecargar.
Existen una serie de operadores que no se pueden sobrecargar:

.  

 ::  

?:  

   sizeof

La sobrecarga de operadores en C++ tiene una serie de restricciones que es necesario tener presente a la hora de manejar operadores sobrecargados:

* Se pueden sobrecargar sólo los operadores definidos en C++

*  La sobrecarga de operadores funciona sólo cuando se aplica a objetos de una clase

No se puede cambiar la preferencia o asociatividad de los operadores en C++

*  No se puede cambiar un operador binario para funcionar con un único objeto

* No se puede cambiar un operador unitario para funcionar con dos objetos

*  No se puede sobrecargar un operador que funcione exclusivamente con punteros

La clave para la sobrecarga de un operador es una función incorporada a C++ que permite al programador sustituir una función definida por el usuario para uno de los operadores existentes.
Para sobrecargar un operador, se debe definir lo que significa la operación relativa a la clase a la cual se aplica. Para hacer esta operación, se crea una función operador, que define su acción. El formato general de una función operador es el siguiente:
                         tipo nombre_clase::operator op (lista_argumentos) 
{...}
tipo es el tipo del valor devuelto por la operación especificada. Los operadores sobrecargados, con frecuencia tienen un valor de retorno que es del mismo tipo que la clase para la cual el operador se sobrecarga.
Las funciones operador deben ser miembro o amigas de la clase que se está utilizando.
Las funciones operador tienen la misma sintaxis que cualquier otra, excepto que el nombre de la función es operator op, donde op es el operador que se sobrecarga.

6.3 Declaración de funciones operador

Las funciones operador u operadores sobrecargados pueden ser o no miembros de una clase. De este modo, se pueden sobrecargar funciones miembro de una clase, así como funciones amigas.
Una función amiga tiene un argumento para un operador unitario y dos para uno binario. Una función miembro tiene cero argumentos para un operador unitario y uno para un operador binario.

6.4 Sobrecarga de operadores unitarios

Consideramos una clase t y un objeto x de tipo t y definimos un operador unitario sobrecargado: ++, que se interpreta como:      operator++(x) o bien como x.operator()
Ejemplo:

class vector

{

double x,y;

  public:

void iniciar(double a, double b){x=a; y=b;}

void visualizar()

{

cout<<"vector "<<x<<","<<y<<endl;

}

double operator++(){x++;y++;}

};

 void main()

{

  vector v;

  v.iniciar(2.5,7.1);

  v++;

  v.visualizar();   // visualiza  3.5  8.1

}

6.5 Versiones prefija y postfija de los operadores ++ y --

La versión prefija del operador de incremento se sobrecarga definiendo una versión de ++ de un parámetro; la versión postfija se sobrecarga definiendo una versión de ++ de dos parámetros, siendo el segundo de tipo int (será un parámetro mudo).

Sobrecargar un operador unitario como función miembro.

class c

{  int x;

   public:

c()  {x=0;}

c(int a)  {x=a;}

c& operator--()  {--x;return *this;}

void visualizar() {cout<<x<<endl;}

};

void main()

{  c ejemplo(6);

   --ejemplo;   //ejemplo.operator--();

}

La función --() está declarada; ya que es una función miembro, el sistema pasa el puntero this implícitamente. Por consiguiente, el objeto que llama a la función miembro se convierte en el operando de este operador.

Sobrecarga de un operador unitario como una función amiga.

class c

{  int x;

   public:

c()  {x=0;}

c(int a)  {x=a;}

friend c& operator--(c y)  {--y.x;return y;}

void visualizar() {cout<<x<<endl;}

};

void main()

{  c ejemplo(6);

   --ejemplo;   //operator--(ejemplo);

}

La función --() está definida; ya que es una función amiga, el sistema no pasa el puntero this implícitamente. Por consiguiente, se debe pasar explícitamente el objeto.

6.6 Sobrecarga de operadores binarios

Los operadores binarios se pueden sobrecargar pasando a la función dos argumentos. El primer argumento es el operando izquierdo del operador sobrecargado y el segundo argumento es el operando derecho. Suponiendo dos objetos x e y de una clase c, se define un operador binario + sobrecargado. Entonces x + y se puede interpretar como operator+(x,y) o como x.operator+(y)
Un operador binario puede, por consiguiente, ser definido:
- como un amigo de dos argumentos
- como una función miembro de un argumento (caso más frecuente)
- nunca los dos a la vez

Sobrecarga de un operador binario como función miembro
El siguiente ejemplo muestra cómo sobrecargar un operador binario como una función miembro:

class binario

{

  int x;

public:

  binario()  {x=0;}

  binario(int a)  {x=a;}

  binario operator + (binario &);

  void visualizar() {cout<<x<<endl;

};

binario binario::operator +(binario &a)

{

  binario aux;

  aux.x=x+a.x;

  return aux;

}

void main()

{

  binario primero(2),segundo(4),tercero;

  tercero = primero + segundo;

  tercero.visualizar();

}

La salida del programas es 6.

Sobrecarga de un operador binario como una función amiga

class binario

{

  int x;

public:

  binario()  {x=0;}

  binario(int a)  {x=a;}

  friend binario operator + (binario &,binario &);

  void visualizar() {cout<<x<<endl;

};

binario binario::operator +(binario &a,binario &b)

{  binario aux;

  aux.x=a.x+b.x;

  return aux;  }

void main()

  binario primero(2),segundo(4),tercero;

     tercero = primero + segundo;

     tercero.visualizar();

}

La salida del programa será 6.

La función operador binario +() está declarada; debido a que es una función amiga, el sistema no pasa el puntero this implícitamente y, por consiguiente, se debe pasar el objeto binario explícitamente con ambos argumentos. Como consecuencia, el primer argumento de la función miembro se convierte en el operando izquierdo de este operador y el segundo argumento se pasa como operando derecho.

6.7 Sobrecargando el operador de llamada a funciones ( )

Uno de los operadores más usuales es el operador de llamada a función y puede ser sobrecargado. La llamada a función se considera como un operador binario
                                    expresión principal (lista de expresiones)
Donde expresión principal es un operando y lista de expresiones (que puede ser vacía) es el otro operando.
La función operador correspondiente es operator() y puede ser definida por el usuario para una clase c sólo mediante una función miembro no estática.

                                        x(i)     equivale a      x.operator() (i)
                                        x(i,j)   equivale a      x.operator()(x,y)

6.8 Sobrecargando el operador subíndice [ ]

El operador [] se utiliza normalmente como índice de arrays. En realidad este operador realiza una función útil; ocultar la aritmética de punteros. Por ejemplo, si se tiene el siguiente array: char nombre[30]; y se ejecuta una sentencia tal como car = nombre[15]; el operador [] dirige la sentencia de asignación para sumar 15 a la dirección base del array nombre para localizar los datos almacenados en esta posición de memoria.
En C++ se puede sobrecargar este operador y proporciona muchas extensiones útiles al concepto de subíndices de arrays. [] se considera un operador binario porque tiene dos argumentos. En el ejemplo
p=x[i]
Los argumentos son x e i. La función operador correspondiente es operator []; ésta puede ser definida para una clase x sólo mediante un función miembro. La expresión x[i] donde x es un objeto de una determinada clase, se interpreta como x.operator[](y).

6.9 Sobrecarga de operadores de flujo

Las sentencias de flujos se utilizan para entradas y salidas. Los flujos no son parte de C++, pero se implementan como clases en la biblioteca de C++. Las declaraciones para estas clases se almacenan en el archivo de cabecera iostream.h. En C++ es posible sobrecargar los operadores de flujo de entrada y salida de modo que pueda manipular cualquier sentencia de flujo que incluya cualquier tipo de clase. Como se definen en el archivo de cabecera iostream.h, estos operadores trabajan con todos los tipos predefinidos, tales como int, long, double,char. Sobrecargando estos los operadores de flujo de entrada y salida, estos pueden además manipular cualquier tipo de objetos de clases.
Ejemplo de sobrecarga de los flujos << y >>

class punto

{

  int x,y;

public:

  punto()  {x=y=0;}

  punto (int xx,int yy)  { x=xx;y=yy;}

  void fijarx(int xx)  { x=xx;}

  void fijary(int yy)  {y=yy;}

  int leerx()  {return x;}

  int leery()  {return y;}

  friend ostream& operator << (ostream& os,const punto &p);

  friend istream& operator >> (istream& is,const punto &p);

};

void main()

{

  punto p;

  cout<<p<<endl;

  p.fijarx(50);

  p.fijary(100);

  cout<<p<<endl;

  cout <<"introducir los valores de x e y\n";

  cin>>p;

  cout<<"se ha introducido"<<p;

}

ostream& operator<<(ostream &os,punto &p)

{

  os <<"x= "<<p.x<<",y= "<<p.y;

  return os;

}

istream& operator>>(istream &is,punto &p)

{

  is >>p.x>>p.y;

  return is;

}

Es posible poner en cascada múltiples objetos en una sentencia de flujo de salida:
                      
punto p1,p2,p3;
                       cout<<p1<<":"<<p2<<":"<<p3;

dAnterior

Indice C++

Siguiente a