Está en la página 1de 43

SOBRECARGA DE

OPERADORES
Laboratorio de Programación I
¿Qué es la sobrecarga de operadores?

 El proceso de sobrecarga de operadores se refiere


a la capacidad de un operador para desarrollar una
función en varios contextos diferentes sin
necesidad de funciones adicionales.
 Ej: el operador +
Nosotros lo entendemos como suma de términos
reales:
suma = a + b // a y b aquí son dos valores float

Sobrecargamos el operador + para la suma de números


complejos:

sumaComplejos = complejoA + complejo B


//objetos complejos
Declaración de operadores
sobrecargados
Sintaxis en C++:
tipo <nombre clase>:: operator operador
([argumentos]);

donde tipo indica el tipo de valor devuelto por la


función específica y operador es uno de los
operadores válidos.
Restricciones en la sobrecarga de
operadores

 Los operadores = y & pueden utilizarse con objetos


de cualquier clase sin sobrecarga
Restricciones en la sobrecarga de
operadores
 No se pueden crear nuevos operadores. Sólo se
pueden sobrecargar los existentes y no se puede
modificar la manera en que funcionan con tipos
predefinidos.

 No es posible cambiar el orden de precedencia de


un operador (siempre se pueden utilizar paréntesis
para forzar el orden de evaluación) ni la
asociatividad.
Restricciones en la sobrecarga de
operadores
 No se puede sobrecargar un operador binario para
crear un operador unario.

 No se puede sobrecargar un operador unario para


realizar operaciones binarias.
Restricciones en la sobrecarga de
operadores
 Cuando se sobrecarga por ejemplo el operador +,
no se sobrecarga el operador +=.

 Igual con – y -=, * y *=, == y !=, etc.

 No se pueden sobrecargar los siguientes


operadores:
. * :: ? : sizeof #
Declaración de funciones operador
 Las funciones operador deben ser miembro o
amigas de la clase que se está utilizando (por
razones de rendimiento).
Si son funciones miembro
 Supongamos que hemos sobrecargado el operador
+ para sumar objetos de una clase.

 Si a y b son dos objetos de dicha clase entonces


a+b implica que el compilador genere la llamada
a.operator+(b):
Si son funciones miembro
 Es decir, la función sobrecargada (como todas las
funciones miembro) utiliza el operador this de
manera implícita para obtener el operando
izquierdo en operaciones binarias.

 Por ello, una función sobrecargada miembro de la


clase tiene cero argumentos para un operador
unario y uno para un operador binario.
Si NO son funciones miembro
 Supongamos que hemos sobrecargado el operador
+ para sumar objetos de una clase.

 Si a y b son dos objetos de dicha clase entonces


a+b implica que el compilador genere la llamada
operator+(a,b):
 tienen un argumento para un operador unario y dos
para uno binario (es decir, se deben listar
explícitamente los parámetros).
 Las funciones miembro operador obligan a que el
operando izquierdo de un operador binario sea un
objeto de la clase.

 Si necesitamos operar entre dos objetos de distintas


clases, se hacen funciones no miembro en la que se
listan los parámetros para los dos operandos.

 Las funciones no miembro se pueden hacer friend para


acceder a datos privados de manera directa, si no hay
que acceder a ellos mediante funciones set y get.
Sobrecarga de operadores unarios
 Un operador unario para una clase puede
sobrecargarse como una función miembro no
estática sin argumentos, o como una función no
miembro con un argumento que debe ser un
objeto o una referencia a un objeto de la clase.
 Supongamos que sobrecargamos el operador unario !
para evaluar que un objeto de la clase cadena está vacía.
 Como una función miembro se definiría:
class cadena {
public:
bool operator!() const;
…..
};

 Si c es un objeto de esa clase, la operación !c que el


compilador genera la llamada c.operator!()
Sobrecarga de operadores binarios
 Un operador binario para una clase puede
sobrecargarse como una función miembro no
estática con un argumento, o como una función no
miembro con dos argumentos (uno de esos
argumentos debe ser un objeto o una referencia a
un objeto de la clase).
 Supongamos que sobrecargamos el operador binario
+ para la clase Racional:

Como una función miembro se definiría:


class Racional{
public:
Racional operator+( const Racional &);
…..
};
Si y y z son objetos de esa clase, la operación
y+z

implica que el compilador genera la llamada

y.operator+(z)
Como una función no miembro se definiría:

class Racional{
friend Racional operator+(const Racional &,
const Racional &);
…..
};

Si y y z son objetos de esa clase, la operación y+z


implica que el compilador genera la llamada
operator+(y,z)
Operador de asignación =
 Si no se define el operador sobrecargado de
asignación, aun así se permite la asignación,
realizando una copia a nivel de miembros de cada
dato miembro.
El problema es cuando los objetos tienen apuntadores a
almacenamiento asignados de forma dinámica, ya que
lo que se crean son dos objetos distintos que apuntan al
mismo almacenamiento dinámico:
•Las modificaciones que uno haga le afectan al otro
•Si uno de ellos llama a su destructor se libera la
memoria compartida, y si el otro sigue haciendo
referencia a esas posiciones se queda en estado
indeterminado.
Operadores ++ y --
 Cuando se sobrecargan los operadores ++ y -- hay
que tener en cuenta que hay que sobrecargar las
dos versiones: preincremento y posincremento, y
predecremento y posdecremento
 Las versiones prefijo se sobrecargan como
cualquier otro operador unario:
fecha & operator++();
para ++f1 el compilador llama a f1.operator++()
O bien,
friend Fecha & operator++(Fecha &);

para
++f1

el compilador llama a

operator++(f1).
Las versiones posfijo deben incluir un segundo
argumento del tipo int para que el compilador las
distinga, aunque no se haga uso (parámetro mudo):

Fecha operator++(int);
para
f1++ el compilador llama a
f1.operator++(0)

O bien,
friend Fecha operator++(Fecha &, int);
para f1++ el compilador llama a
operator++(f1,0).
Operadores de extracción e inserción
de flujo >> y <<
 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 encabezados iostream.h.
Operadores de extracción e inserción
de flujo >> y <<
 En iostream.h estos operadores están
sobrecargados para trabajar con todos los tipos
predefinidos, tales como int, long, double, char….
 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 objetos de clases definidas por el
usuario.
Algunas notas sobre entrada/salida:
streams
 Para gestionar la entrada/salida, C++ dispone de
un buen número de clases, cuya interfaz se
encuentra especificada en iostream.h.

 Estas clases no son parte del lenguaje, pero están


fuertemente asociadas con él.

 El propósito de estas clases es proporcionar un


mecanismo para la E/S de objetos
ios
 Clase base de la jerarquía.
 Define los estados asociados con cada stream de
forma que por ejemplo, sepamos cuando ha
finalizado una operación.
 Define los manejadores para formatear la salida.
ostream
 Output stream,
 proporciona la funcionalidad necesaria para la
salida de datos predefinidos.
 cout, cerr y clog son objetos predeterminados de
esta clase.
istream
 Input stream,
 proporciona la funcionalidad necesaria para la
entrada de datos predefinidos.
 cin es un objeto predeterminado de esta clase.
Algunas notas sobre entrada/salida:
objetos predeterminados
 Desde el punto de vista de la POO, cin, cout, err y clog
son cuatro objetos.
 cin es un objeto predefinido de la clase istream, cout, cerr
y clog son objetos predefinidos de la clase ostream
 cin:
 Toma caracteres de la entrada estándar: teclado
 cout
 Pone caracteres en la salida estándar : pantalla
 cerr y clog
 Pone mensajes de error en la salida estándar (pantalla)
Sobrecarga del 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
objeto de la clase y lista de expresiones (que puede
estar vacía) son objetos de otras clases.
Sobrecarga del operador de llamada a
funciones: ()
 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:
c operator()(int, int);

 Si x es un objeto de clase c: x(i,j) equivale a


x.operator()(i,j)
Resumen
 La sobrecarga de operadores hace que el programa
sea más claro que mediante llamadas de
funciones.

 El operador sobrecargado debe realizar las mismas


funciones o parecidas que las que realizan los
operadores sobre los objetos de los tipos
integrados.
Resumen
 Hay algunos operadores que requieren ser
sobrecargados por pareja, es decir, que si
sobrecargamos uno de ellos tenemos que
sobrecargar también su opuesto.

 Si sobrecargamos un operador y no sobrecargamos


su pareja, el compilador nos avisará con un error.
Resumen
 Algunos de estos son:
 operador == y el operador !=
 operador > y el operador <
 operador >= y el operador <=

 No todos los operadores pueden ser


sobrecargados. Hay un listado de restricciones.
Resumen
 Un operador Δ en C++ se puede sobrecargar para
ser usado sobre un nuevo tipo definiendo una
función con nombre
 Operator Δ()
 Por ejemplo, para sobrecargar + para el tipo Color,
usamos una función
Color operator+ (Color c1, Color c2);
que define cuál es el Color resultante de c1+c2.

 Se pueden escribir instrucciones de la forma:


Color a = ROJO; b= AMARILLO; c;
c = a+b;
 Se pueden sobrecargar los operadores de salida <<
y de entrada >> definiendo operator<<() y operator
>>().

 Por ejemplo, para sobrecargar el operador de


salida para el tipo Color, podemos usar:
 En Color.h:
ostream & operator<< (ostream & sal, Color col);

Se devuelve una referencia al ostream de forma


que se pueda encadenar << como por ejemplo:
cout << unColor << endl;
 En Color.cpp
ostream & operator<< (ostream & sal, Color col);
{
//conversor de Color a string
switch (col)
{
case ROJO: sal << “ROJO”; break;
// ….
}
return sal;
};
 La sobrecarga del operador de entrada es similar:

 En Color.h:
istream & operator>>(istream & ent, Color col);

 En Color.cpp
istream & operator>> (istream & ent, Color col);
{
//leer el nombre del color en una variable string
// se debe usar #include <string.h>
// convertirlo a mayúsculas usando toupper()
// conversor de string a Color: asignar a col el valor de tipo Color
que corresponda al string de entrada;
// devolver ent;
};

También podría gustarte