2. La
sobrecarga
de
operadores
es
una
herramienta
que
nos
proporciona
algunos
lenguajes
como
C++.
Esta
propiedad
nos
permite
definir
el
significado
de
uno
o
varios
operadores
en
el
contexto
de
una
determinada
clase
de
objetos.
Definición
+ -‐ * / % ^ & |
~ ! = < > += -‐= *=
/= %= ^= &= |= << >> >>=
<<= == != <= >= && || ++
_ -‐>* , -‐> [
] (
) new delete
new[
] delete[
]
Operadores que pueden ser sobrecargados
3. Sobrecarga
de
operadores
. Selector
directo
de
componente
.* Operador
de
indirección
de
puntero-‐a-‐miembro
:: Operador
de
acceso
a
ámbito
?: Condicional
# Directiva
de
preprocesado
# # Directivas
de
preprocesado
sizeof,
typeid
Operadores que no se pueden sobrecargar
4. • 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.
Restricciones
5. class complejo //Nombre de la clase
{
public :
complejo( double = 0.0, double = 0.0 ); //Constructor
complejo operator + ( const complejo & )const; //Sobrecarga
private:
double real, imaginario;
};
complejo::complejo( double a, double b ) // Constructor de la clase
{
real = a; imaginario = b;
}
complejo complejo::operator + (const complejo &a) const
{ complejo c; //Define un objeto complejo
c.real = real + a.real; //Define de la operación llevada a cabo por el operador
c.imaginario = imaginario+a.imaginario;
return c; //Retorno del valor adquirido
}
Ejemplo la clase complejo
6. void main( ) //Programa Principal
{
double x, y, w, z; //Definir variables para los objetos
cout<<“nDigite el valor real del primer complejo: “; cin>> x;
cout<<“nDigite el valor imaginario del primer complejo: “; cin>> y;
cout<<“nDigite el valor real del segundo complejo: “; cin>> w;
cout<<“nDigite el valor imaginario del segundo complejo: “; cin>> z;
complejo A(x,y), B(w,z), C; //Definición de los objetos
C = A + B; //Uso de la Sobrecarga del operador +
/*Se imprimen los resultados, para esto se debe tener un método adicional que no esta
implementado en este ejemplo.*/
}
Ejemplo la clase complejo
7. Funciones
como
miembros
de
la
clase
o
como
friend
Una función operador no miembro necesita ser friend si dicha función debe
acceder de manera directa a miembros privados o protegidos de esa clase.
Cuando se sobrecargan los operadores [ ], ( ), -‐>, o cualquiera de los
operadores de asignación, la función de sobrecarga del operador se debe
declarar como una clase miembro; para los demás operadores, las funciones
de sobrecarga pueden ser funciones no miembro.
Cuando se implementa como función miembro, el operando debe ser un
objeto (o una referencia hacia un objeto) de la clase del operador.
Si el operando debe ser un objeto de una clase diferente, esta función
operador debe implementarse como una función no miembro.
8. Operadores
de
inserción
y
de
extracción
de
flujo
C++ puede introducir y mostrar los tipos de datos integrados mediante el
operador de extracción >> y de inserción de flujo <<
El operador sobrecargado << debe tener un operador izquierdo de tipo
ostream & (tal como el objeto cout en: cout << objetoClase).
El operador sobrecargado >> debe tener un operando izquierdo de tipo
istream & (tal como el objeto cin en la expresión: cin >> objetoClase)
10. Sobrecarga
de
operadores
unarios
• Los
operadores
unarios
(tienen
un
único
operando)
que
podemos
sobrecargar
son:
+
-‐ *
/ % ++
-‐-‐,
etc.
• Además,
al
tratarse
de
operadores
unarios
sólo
tomarán
un
parámetro
que
deberá
ser
del
mismo
tipo
de
la
clase
donde
se
declara
el
operador.
• No
existen
restricciones
en
el
tipo
devuelto
excepto
en
el
caso
de
los
operadores
++ y
-‐-‐ que
deberán
devolver
el
mismo
tipo
que
toman
como
parámetro.
11. • Los
operadores
binarios
tienen
dos
operandos.
Este
tiene
que
tomar
dos
parámetros
y
al
menos
uno
de
ellos
debe
ser
del
tipo
de
la
clase
donde
se
declara,
aunque
sobre
el
tipo
devuelto
por
el
operador
no
se
impone
ningún
tipo
de
restricción.
• Hay
algunos
operadores
que
requieren
ser
sobrecargados
por
pareja.
Estos
son:
• Operador
== y
el
operador
!=
• Operador
> y
el
operador
<
• Operador
>= y
el
operador
<=
Sobrecarga
de
operadores
binarios
13. class Arreglo
{
friend ostream &operator<<(ostream &, const Arreglo &);
friend istream &operator>>(istream &, Arreglo &);
public:
Arreglo (int = 10); //Constructor predeterminado
Arreglo (const Arreglo &); //Constructor de copia
~Arreglo(); //Destructor
int obtieneTamanio() const;
const Arreglo &operator=(const Arreglo &);
int operator==(const Arreglo &) const;
int operator!=(const Arreglo &derecha) const
{
return !(*this == derecha); //invoca a Arreglo::operator==
}
int &operator[](int); //El operador de subíndice para objetos no constantes
const int &operator[](int) const; //Operador de subíndice para obj constantes
private:
int tamanio;
int *ptr;
}; //fin definición de la clase
Ejemplo la clase Arreglo
14. Arreglo::Arreglo(int tam) //Constructor predeterminado
{
tamanio = (tam > 0 ? tam : 10);
ptr = new int[tamanio]; //Crea espacio para el arreglo
for (int i = 0 ; i < tamanio ; i++)
ptr[i] = 0;
}
//Constructor de copia
Arreglo::Arreglo(const Arreglo &arregloAcopiar): tamanio(arregloAcopiar.tamanio)
{
ptr = new int[tamanio];
for (int i = 0 ; i < tamanio ; i++)
ptr[i] = arregloAcopiar.ptr[i]; //Copia dentro del objeto
}
Ejemplo la clase Arreglo
15. Arreglo::~Arreglo() //Destructor
{
delete []ptr; //Reclama espacio del arreglo
}
int Arreglo::obtieneTamanio() const
{
return tamanio;
}
/*Determina si dos arreglos son iguales */
int Arreglo::operator==(const Arreglo &derecha) const
{
if (tamanio != derecha.tamanio)
return 0;
for (int i = 0 ; i < tamanio ; i++)
if (ptr[i] != derecha.ptr[i])
return 0;
return 1;
}
Ejemplo la clase Arreglo
16. /*Operación de asignación sobrecargado; la devolución de const evita: (a1 = a2) = a3 */
const Arreglo &Arreglo::operator=(const Arreglo &derecha)
{
if (&derecha != this) //verifica la auto asignación
{
/*Para arreglos de diferentes tamaños, libera por la izquierda, y asigna por la izquierda*/
if (tamanio != derecha.tamanio)
{
delete []ptr;
tamanio = derecha.tamanio;
ptr = new int[tamanio];
}
for (int i = 0 ; i < tamanio ; i++)
ptr[i]=derecha.ptr[i]; //Copia el arreglo dentro del objeto
}
return *this; //Por ejemplo, habilita X = Y = Z
}
Ejemplo la clase Arreglo
17. /*El operador subindice sobrecargado para el retorno de referencias a arreglos no constantes, crea un lvalue */
int &Arreglo::operator[](int subindice)
{
if (subindice < 0 || subindice >= tamanio)
{
cout << fixed<< left<<showpoint;
cout<<"nError: Subindice, fuera de rango "<<subindice;
exit(1); //Termina el programa
}
return ptr[subindice]; //Retorno de referencia
}
/*El operador subindice sobrecargado para el retorno de referencias a arreglos constantes, crea un rvalue */
const int &Arreglo::operator[](int subindice) const
{
if (subindice < 0 || subindice >= tamanio)
{
cout<<"nError: Subindice, fuera de rango "<<subindice;
exit(1); //Termina el programa
}
return ptr[subindice]; //Retorna una referencia constante
}
Ejemplo la clase Arreglo
18. /*Operador de entrada sobrecargado para la clase Arreglo; introduce los valores en todo el arreglo */
istream &operator>>(istream &entrada, Arreglo &a)
{
for (int i = 0 ; i < a.tamanio ; i++)
entrada >> a.ptr[i];
return entrada;
}
/*Operador de salida sobrecargado para la clase Arreglo */
ostream &operator<<(ostream &salida, const Arreglo &a)
{
for ( int i = 0 ; i < a.tamanio ; i++)
{
salida<<" "<<a.ptr[i];
if ((i+1)%4 == 0) salida<<endl;
}
if (i % 4 == 0) salida<<endl;
return salida;
}
Ejemplo la clase Arreglo
19. int main()
{
Arreglo enteros1(15);
Arreglo enteros2;
cout<< "nEl Tamaño del arreglo enteros1 es " << enteros1.obtieneTamanio();
cout<< "nArreglo despues de la inicializacion:n" << enteros1;
cout<<"nnIntroduzca 25 enteros : n";
cin>>enteros1>>enteros2;
cout<< "nAl Introducir los arreglos contienen: n";
cout<< "enteros1:n" << enteros1 << "nenteros2:n" << enteros2;
cout<< "nEvaluando: enteros1 != enteros2 n"; //Utiliza el operador de desigualdad (!=) sobrecargado
if (enteros1 != enteros2) cout<<"enteros1 y enteros2 no son igualesn";
/*Crea el arreglo enteros3 utilizando enteros1 como un inicializador; imprime el tamaño y el contenido */
Arreglo enteros3(enteros1); //Llama al constructor de copia
cout<< "nEl tamaño del arreglo enteros3 es "; cout<<enteros3.obtieneTamanio();
cout<< "nArreglo después de la Inicialización:n” << enteros3;
cout<< "nAsignación de enteros2 a enteros1:n";
enteros1 = enteros2; //Uso del operador de asignación sobrecargado (=)
cout<< "nenteros1:n” <<enteros1;
cout<< "nenteros2:n” <<enteros2;
Ejecutando la clase Arreglo
20. Ejecutando la clase Arreglo
//Uso del operador de igualdad sobrecargado
cout<< "nEvaluando: enteros1 == enteros2n";
if (enteros1 == enteros2)
cout<< "nenteros1 y enteros2 son igualesn";
//Uso del operador de subíndices sobrecargado para crear un rvalue
cout<< "nenteros1[5] es ” << enteros1[5];
//Uso del operador de subíndices sobrecargado para crear un lvalue
cout<< "nnAsignación de 1000 a enteros1[5]n";
enteros1[5]=1000;
cout<< "nenetros1n” <<enteros1;
//Intento de uso de un subíndice fuera de rango
cout<< "nIntenta asignar 1000 a enteros1[15]” << endl;
enteros1[15]=1000;
cout<< "nenetros1n” << enteros1;
return 0;
}