lunes, 30 de junio de 2008

Sobrecarga de funciones y operadores en C++ (Parte 1)

CHenry [chenry@lab.matcom.uh.cu]

Un tema recurrente en el mundo de la programación, y una de las cosas a tener en cuenta cuando se elije en que lenguaje se construye determinado software, teniendo en cuente el QUE hace y COMO lo hace es el tema de la sobrecarga por ejemplo cuando determinada estructura de datos puede inicializarse de varias formas, los distintos lenguajes de programación poseen alguna herramienta para realizar esta tarea y los que no lo poseen o no lo necesitan por sus características o buscan alguna manera de simularlo. 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.

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.

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.

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.

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
}

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.



Artículos relacionados


No hay comentarios: