Anda di halaman 1dari 4

Programacin I

Actividad 17 Conferencia # 9 Homonimia de operadores.


SUMARIO:
-Introduccin.
-Homonimia de operadores unarios y binarios.
-Operador de insercin y extraccin de flujo. Clases ostream e istream.
BIBLIOGRAFA:
LT Tomo 3 captulo 18. Ejercicios 18.9, 18.15, 18,20.
OBJETIVOS
Que los estudiantes conozcan cmo se programa la homonimia de operadores as como las ventajas desde el
punto de vista del programador usuario de clases.
Introduccin
La homonimia de operadores es la capacidad que tiene C++ para redefinir la mayora de operadores conocidos
(pg. 682 fig. 18.1) de manera que estos puedan ser aplicados a objetos de clases definidas por el usuario.
Ejemplo:
Para sumar dos nmeros enteros se realiza lo siguiente:
int a,b;
cin >> a; cin >> b;
int r = a+b;
Esto es posible ya que a y b son enteros sobre los cuales el operador + est definido. Y lo que realiza + es la
suma aritmtica de dos cantidades enteras. Lo mismo sucede con float o double.
Hay muchos operadores que se pueden sobrecargar, sin embargo la premisa que debemos tener a la hora de
definir cules sern aplicados a una clase, es que el mismo sea semnticamente correcto, o lo que es lo mismo
que el operador tenga algn sentido vlido para la clase. Algunos ejemplos son:
1. No tiene sentido sumar dos estudiantes, ni dos trabajadores, pero si definir el operador << y el >> para
imprimirlos o introducir sus datos desde teclado.
2. Dos lista pudieran sumarse en el sentido de concatenar sus datos, esto es correcto.
La sobrecarga de un operador se puede realizar de dos formas: como mtodo de clase o como funcin
independiente. Para ello debemos tener en cuenta si el operador es unario o binario.
Operador unario: Es aquel que se aplica a un operando: , &, ++, --, si se desea sobrecargar un Operador unario
para que sea aplicado a un objeto T, tenemos la siguientes opciones:

Conf # 1 Pg 1 de 4

// como miembro de clase


class T{
public:
T& operator!();
}
T& T::operator!(){
// implementacin
}

// como funcin independiente amiga


class T{
friend T& operator!(T&);
public:
}
T& operator!(T& param){
// implementacin
}

Observaciones:

La palabra clave operator seguida del operador que se desea sobrecargar es el nombre de la funcin.
Los parmetros que recibe la funcin son los operandos. En el caso de ser la funcin miembro de clase.
El operando de la derecha es siempre el propio objeto (*this).
El prototipo de la funcin es MUY IMPORTANTE. Por ejemplo, si usted va a realizar la operacin !
sobre un objeto de la clase T debe tener claro cul es el comportamiento que desea para el Tipo T cuando
el operador se aplique varias veces:
Al definir un objeto usando la declaracin:

T t; la operacin !t: debe invertir el objeto y se modifica el

objeto t. Si se aplica dos veces: !!t, el objeto debe quedar intacto. Desglosando estas operaciones
podemos ver que se divide en dos partes:
1-

!t implica que el compilador invoque a la funcin miembro t.operator!() esta funcin modifica

el objeto y devuelve una referencia al propio objeto.


2- Luego se vuelve a aplicar t.operator!() sobre el objeto devuelto. Si la operacin es simtrica no
deben existir problemas. Ej: una lista de elementos ordenados de mayor a menor si se invierte queda
entonces de menor a mayor. Si se vuelve a invertir queda en el estado original.
Es muy importante que el valor devuelto sea una referencia T& al propio objeto modificado, de lo contrario el
resultado de la operacin ser una copia del objeto y la segunda operacin no tendra validez ya que no se
aplicara a t sino a un objeto temporal devuelto por la primera llamada.
Operador binario: Es aquel que se aplica a dos operandos: +, - , *, /, >, <, etc. Este caso es ms complejo
debido a que pueden existir innumerables funciones homnimas. Por ejemplo si a la clase T anterior se le
definiera el operador +, deberamos pensar:
Qu es lo que se debera sumar a un objeto t1 de la clase T?
- Puede que a t1 se le pueda sumar un objeto t2 de la propia clase T. Ej: t1+t2.
- Puede que a t1 se le pueda sumar un nmero entero. Si es el caso puede que se encuentre a la derecha o a
la izquierda del operador: t1+5 5+t1.
- Puede que a t1 se le pueda sumar un objeto f2 de otra clase F definida previamente: t1+f2.
Para cada una de esas posibilidades entonces debera existir una funcin homnima. Debe quedar claro que si
el primer operando no es un objeto de la clase, el operador obligatoriamente debe ser definido como funcin
independiente (usualmente funcin amiga).
Conf # 1 Pg 2 de 4

(Rol/PUC)
Mtodo de clase (Rol/PC)
t1+t2
T operator+(const T& t2);
t1+5
T operator+(int i2);
5+t1
t1+f2
T operator+(const F& f2)
f2+t1
Donde: t1, t2 son de tipo T y f2 son de tipo F.

Funcin independiente Amiga(Rol/PC)


friend T operator+( const T& ta, const T& tb);
friend T operator+( const T& ta, int ib);
friend T operator+( int ia, const T& tb)
friend T operator+( const T& ta, const F& fb);
friend T operator+( const F& fa, const T& tb)

Operador de insercin y extraccin de flujo.


En los programas que hemos utilizado durante este curso, para imprimir hemos utilizado a cout y cin.
Incluyendo la biblioteca iostream de C++. Es hora de profundizar un poco en ellas:
cin y cout son objetos que pertenecen a las clases istream y ostream respectivamente. Estos objetos estn
siempre visibles a nosotros gracias a la biblioteca iostream.h que se encarga de inicializarlos por nosotros. Al
ejecutar una operacin como la siguiente:
cout << 5, en realidad estamos utilizando la sobrecarga del operador <<, que est definido en la clase ostream.
class ostream{
public:
ostream& operator<<(int);
ostream& operator<<(char);
ostream& operator<<(char*);
ostream& operator<<(double);
}
Luego, en la instruccin anterior cout << 5, realmente lo que se ejecuta es cout.operator<<(5) que es un
mtodo de la clase ostream. Lo mismo sucede con cin y la clase istream.
Si deseramos que nuestra clase T trabajara de la misma forma que los tipos predefinidos de C++, de forma que
se pueda ejecutar la siguiente operacin: cout << t1 entonces tenemos dos variantes:
-

Redefinir la clase ostream sobrecargando ostream& operator<<(const T&);


Definir una sobrecarga del operador << en la clase T. teniendo en cuenta que el operador de la derecha
es del tipo ostream. O sea solo tendremos la posibilidad de sobrecargarlo como funcin independiente.

La primera opcin es poco menos que absurda, as que nos queda solo una opcin:
friend ostream& operator<<( const ostream& output, const T& tb);
El tipo devuelto es necesario para poder concatenar llamadas de este tipo ejemplo:
cout << t1 << t2;
En este caso el proceso es el siguiente:
1ro - cout = operator<<( cout, t1);
2do- cout = operator<<( cout, t2);
Conf # 1 Pg 3 de 4

Ejemplo:
Vamos a estudiar el ejemplo del libro de texto donde se define una clase Array que manipula un arreglo creado
dinmicamente: La ventaja de utilizar una clase Array para los PUC ser la siguiente:
1. Permitir controlar al acceso a los elementos de arreglo sin que se produzcan errores de acceso debido a
mala indexacin.
int a[3]= {1,23,-5};
a[7] = 10 // error;
2. Permitir comparar arreglos con los operadores == =:
int b = {1, 23,-5};
a == b compara los punteros a entero a y b. Pero nosotros quisiramos que nos diga si los arreglos
contienen la misma cantidad de elementos y adems si coinciden en cada una de las posiciones.
3. Permitir asignar un arreglo a otro usando solo el operador.
int c = {5, 78,-23};
a = c;
4. Al escribir cout << a, se impriman los elementos del arreglo y no la direccin del puntero en memoria.
class Array {
friend ostream &operator<<(ostream &, const Array &);
public:
Array(int=10);
Array(const Array&);
~Array();
int getSize() const;
const Array& operator=(const Array&);
int operator==(const Array&) const;
int& operator[](int);
private:
int *ptr;
int size;
};
Observaciones:
operator<<: Siempre se sobrecarga como funcin independiente pues el operando de la derecha es de
una clase diferente a la cual se quiere aplicar el operador. En este caso ostream.
Array(const Array&): Es el constructor de copia redefinido ya que el arreglo se crear dinmicamente.
operator=: Es el operador de asignacin sobrecargado para que un objeto Array pueda ser asignado a
otro. En C++ siempre se proporciona uno por defecto (similar al constuctor de copia), que copia bit a bit
la memoria de un objeto a otro. Cuando esta copia bit a bit no es semnticamente correcta, entonces
debe sobrecargarse. Este es el caso debido a que la clase almacena un puntero que indica una zona de
memoria pedida dinmicamente. Esta funcin debe devolver una copia del objeto
operator[] Permitir aplicar la notacin de subindices a los objetod de la clase tal y como se hace en un
arreglo de C/C++. El valor devuelto ser una referencia a un elemento de arreglo. Esto permitir hacer
procesos de lectura y escritura: Ej: Array a; a[1] = 10; int b = a[1];
Conclusiones:

Conf # 1 Pg 4 de 4