Tema: Sobrecarga de Operadores.

Anuncio
Programación II. Guía 7
1
Facultad:
Ingeniería
Escuela:
Computación
Asignatura: Programación II
Tema: Sobrecarga de Operadores.
Objetivos
ƒ
Describir como redefinir (sobrecargar) operadores para que funcionen con nuevos tipos de
datos.
ƒ
Diferenciar sobrecarga de operadores binarios y unarios.
ƒ
Identificar cuando sobrecargar operadores.
ƒ
Implementar programas en C++ que sobrecarguen operadores unarios.
Materiales y Equipo
• Computadora con el software DevC++
• Guía Número 7
Introducción
Recordemos que los operadores son un tipo de tokens que indican al compilador la realización
de determinadas operaciones sobre variables u otros objetos (los operandos).
Por ejemplo, cuando encontramos una expresión del tipo:
z = x + y;
// suponemos que x, y, z son de tipo int
(1)
Sabemos que la sentencia contiene dos operadores; el de suma (+) y el de asignación (=); que
estos operadores actúan (operan) sobre objetos de tipo int, y que sus reglas de uso y su
significado (que resultados se obtienen) están perfectamente definidos en el lenguaje.
Los operadores aceptan uno o varios operandos de tipo específico (alguno de los tipos básicos
preconstruidos en el lenguaje), produciendo y/o modificando un valor de acuerdo con ciertas
reglas.
Sin embargo, C++ permite redefinir la mayor parte de ellos. Es decir, permite que puedan
aceptar otro tipo de operandos (distintos de los tipos básicos) y seguir otro comportamiento, al
2
Programación II, Guía 7
tiempo que conservan el sentido y comportamiento originales cuando se usan con los
operandos normales.
Esta posibilidad, que recibe el nombre de sobrecarga del operador, es una consecuencia del
polimorfismo y hace posible que en la expresión:
c = d + e;
// suponemos que c, d, e son de tipo UnaClase (2)
el sentido de la suma y el de asignación sean totalmente específicos y distintos que el de la
expresión “1” anterior cuando se utilizaron los mismos operadores con operandos tipo int.
NOTA: La primera e importantísima advertencia es que la sobrecarga se refiere y tiene
aplicación solo cuando los operandos son instancias de clases. Es decir, no es posible
modificar el sentido de la suma y asignación de la expresión “2” si c, d y e fuesen enteros o de
cualquiera de los tipos básicos preconstruidos en el lenguaje.
La sobrecarga de los operadores es una de las características más interesantes de C++ y,
naturalmente, de la programación orientada a objetos.
La sobrecarga hace posible manipular objetos de clases con operadores estándar tales como
+, *, [ ] y <<.
Esta propiedad de los operadores permite redefinir el lenguaje C++, que puede crear nuevas
definiciones de operadores,
La sobrecarga es una característica que ofrece el lenguaje C++ para aplicar una misma
operación, a través de operadores o funciones, a diferentes tipos de datos.
Se pueden sobrecargar los operadores predefinidos y funciones definidas por el usuario.
La sobrecarga permite generalizar el uso de operadores y funciones.
Sobrecarga de Operadores.
Es el proceso de asignar dos ó más operaciones al mismo operador.
En otras palabras, permite asignar una o más funciones adicionales a un operador estándar,
con el fin de que ésta sea llamada según el contexto en el cual se utilice el operador.
Un operador sobrecargado no puede tener parámetros predeterminados.
Para sobrecargar un operador, y aplicarlo en operaciones entre clases, se usa la función
especial operador.
Una función operador es una función cuyo nombre consta de la palabra reservada operator
seguida de un operador unitario o binario que se sobrecargará.
Programación II. Guía 7 3
La sintaxis para sobrecargar un operador es la siguiente:
<tipo de dato> <Nombre de clase> operator <#> (lista de parámetros)
{
//instrucciones que forman el cuerpo del operador
}
Donde:
•
tipo de dato: indica el tipo de dato que produce el operador sobrecargado, por lo
general es la referencia del objeto.
•
Nombre de clase: es el nombre de clase en la que estamos aplicando sobrecarga.
•
operator: es una palabra reservada utilizada para realizar la sobrecarga
•
#: operador que estamos sobrecargando.
•
Lista de parámetros: es la lista de objetos (en referencia) o variables que se
procesarán en la sobrecarga, si la operación es unaria no tendrá parámetros, si la
operación es binaria tendrá un parámetro.
Operadores sobrecargables.
El lenguaje C++ permite redefinir la funcionalidad de los siguientes operadores:
+
-
>>
*
/
%
>>= <<= ==
^
&
~
!= <= >=
!
=
&&
<
|| ++
>
+= -=
--
->*
*=
, ->
/=
%=
[]
()
^=
new
&=
|= <<
new[] delete
delete[]
Los operadores +, -, * y & son sobrecargables en sus dos versiones, unaria y binaria.
Es decir: suma binaria +; más unitario +; multiplicación *; indirección *; referencia & y manejo
de bits &.
Es notable que C++ ofrezca casos de operadores sobrecargados incluso en su Librería
Estándar. Por ejemplo, los operadores == y != para la clase type_info.
Sin embargo, la posibilidad de sobrecarga no se extiende a todos los operadores.
Excepciones:
En la lista anterior, puede verificarse que todos los operadores pueden ser sobrecargados,
incluyendo new, new [ ], delete y delete [ ], excepto los siguientes:
•
Selector directo de componente .
•
Operador de indirección de puntero a miembro .*
•
Operador de acceso a ámbito ::
•
Condicional ternario ?:
Programación II, Guía 7
4
•
Directivas de preprocesado # y # #
•
sizeof: informa del tamaño de almacenamiento utilizado por cualquier objeto, sea un
tipo básico o derivado.
•
typeid: identifica un operador con el que puede obtenerse el tipo de objetos y
expresiones en tiempo de ejecución. Permite comprobar si un objeto es de un tipo
particular, y si dos objetos son del mismo tipo.
Sobrecarga de Operadores Binarios.
Un operador binario tiene dos operandos o argumentos, uno a cada lado del operador.
El operador “/”, por ejemplo, es binario. Algunos operadores tales como “+” son unitarios y
binarios, dependiendo de su uso.
Los operadores binarios pueden ser sobrecargados de dos formas:
a. Declarando una función miembro no estática que acepte un argumento
b. Declarando una función no miembro (generalmente friend) que acepte dos argumentos.
Según lo anterior, y dependiendo de la declaración, si @ representa el operador binario, la
expresión x @ y entre miembros de una clase C puede ser interpretada como cualquiera de
las dos formas:
a. x.operator @ (y)
b. operator @ (x, y)
Nota: recuerde la versión a parece recibir solo un argumento, pero en realidad recibe dos si se
considera el argumento implícito this, de forma que podría considerarse:
x.operator @ (C * this, y)
siendo: C * this = &x
En otras palabras, un operador binario se puede sobrecargar pasando a la función dos
argumentos si no es función miembro. El primer argumento es el operando izquierdo del
operador sobrecargado y el segundo argumento es el operando derecho, si la función no es
miembro de la clase.
Consideremos un tipo de clase T y dos objetos x1 y x2 de tipo T
Definamos un operador binario “+” sobrecargado, entonces:
x1 + x2 se interpreta como: operator + (x1, x2)
Programación II. Guía 7 5
Un operador binario puede, por consiguiente, ser definido así:
•
Como una función de dos argumentos
•
Como una función miembro de un argumento (el caso más frecuente)
•
Nunca las dos a la vez.
Sobrecarga de los operadores de manejo de flujos de entrada “>>” y de flujos de salida
“<<” Binarios.
Un caso especial es la sobrecarga de los operadores “<<” y “>>” utilizados en la salida u
entrada de datos respectivamente. Estos operadores se encuentran definidos en la biblioteca
iostream de C++.
En el caso de la entrada de datos del teclado a la aplicación, se establece una relación entre
una referencia a un objeto de la clase istream y una referencia a un objeto de la clase en la
cual se está incluyendo la sobrecarga.
La sintaxis es la siguiente:
friend istream & operator >> (istream &, <Nombre de clase> &);
En el caso de la salida de datos de la aplicación a la pantalla, se establece una relación entre
una referencia a un objeto de la clase ostream y una referencia a un objeto de la clase en la
cual se está incluyendo la sobrecarga.
La sintaxis es la siguiente:
friend ostream & operator << (ostream &, <Nombre de clase> &);
Observe que las funciones que se obtienen al sobrecargar los operadores se declaran como
amigas (friend) de la clase en la cual se insertaron. Esto es para que dichas funciones,
externas a la clase, puedan tener acceso a los miembros privados de la misma.
Procedimiento
Ejemplo 1:
En C++, el operador “+” no puede utilizarse para concatenar cadenas.
Sin embargo, si utilizamos una clase propia llamada Cadena, podríamos sobrecargar el
operador “+” para realizar la concatenación de cadenas, como se muestra en el siguiente
ejemplo:
6
Programación II, Guía 7
#include <iostream>
#include <string.h> // Para las funciones de manejo de cadenas: strcpy, strlen y strcat
using namespace std;
class Cadena
{ private:
int longitud;
char *ptrCadena;
// longitud de la cadena
// Puntero a la cadena de caracteres
public:
Cadena (char [ ]= "");
Cadena (Cadena &);
~Cadena();
int long_cadena ();
//constructor predeterminado
//constructor por copia
//destructor
//devuelve longitud de la cadena
// Funciones para sobrecarga de operadores
Cadena & operator + (Cadena &); //concatenación
/* Sobrecarga de los operadores de manejo de flujos de entrada ">>" y de flujos de
salida "<<" */
friend ostream & operator << (ostream &, Cadena &);
friend istream & operator >> (istream &, Cadena &);
};
Cadena :: Cadena (char * cadena)
//Constructor por defecto
{
longitud = strlen(cadena);
ptrCadena = new char[longitud + 1];
// Creación dinámica
if(ptrCadena == NULL)
{ cout<<"No hay memoria";
exit(0);
}
strcpy(ptrCadena, cadena);
// Se verifica si hay memoria disponible
// Se copia el contenido de cadena en el objeto creado
}
Cadena :: Cadena (Cadena & copia)
{
longitud = strlen(copia.ptrCadena);
ptrCadena = new char[longitud + 1];
//Constructor copia
if(ptrCadena == NULL)
// Se verifica si hay memoria disponible
{ cout<<"No hay memoria";
exit(0);
}
strcpy(ptrCadena, copia.ptrCadena); /* Se copia el contenido de copia en el objeto
creado*/
}
Programación II. Guía 7 7
Cadena :: ~Cadena()
{
delete [ ] ptrCadena;
}
// Sobrecarga del operador "+" para que permita concatenar cadenas
Cadena & Cadena :: operator + (Cadena & s)
{
char *temps = ptrCadena;
longitud += s.longitud;
ptrCadena = new char[longitud+1];
if(ptrCadena == NULL)
{ cout<<"No hay memoria";
exit(0);
}
// Se verifica si hay memoria disponible
strcpy(ptrCadena, temps);
// Se copia el contenido de temps en el objeto creado
strcat(ptrCadena, s.ptrCadena); /* Se realiza la concatenación del contenido de s
con el objeto creado*/
delete [ ] temps;
// Se libera memoria reservada con new
return *this;
}
int Cadena :: long_cadena ()
{
return longitud;
}
// Sobrecarga del operador de entrada ">>"
ostream & operator<< (ostream & salida, Cadena & s)
{
salida<< s.ptrCadena;
return salida;
}
// Sobrecarga del operador de salida "<<"
istream & operator>> (istream & entrada, Cadena & s)
{ entrada>> s.ptrCadena;
return entrada;
}
int main()
{ char cad1[20], cad2[20];
system("cls");
cout << "Introducir primer cadena: ";
gets(cad1);
cout << "Introducir segunda cadena: ";
gets(cad2);
Cadena s1(cad1), s2(cad2), s3;
//Creamos los objetos de tipo cadena
8
Programación II, Guía 7
//probando operador sobrecargado de concatenación
cout << endl << endl << "Resultado de concatenar Cadenas s1 y s2: " << endl;
s3 = s1 + s2;
cout << "s3: " << s3;
//prueba el constructor de copiado
Cadena *s4= new Cadena(s2);
cout << endl << endl << "Constructor copia para *s4: " << *s4;
//prueba del operador de asignación =
cout << endl << endl << "Asignando s3 a *s4, *s4: ";
*s4 = s3;
cout << *s4
caracteres.";
<< endl << endl << "Longitud de s4: " << s4 -> long_cadena() << "
system("pause>nul");
return 0;
}
Ejemplo 2:
En este ejemplo se sobrecargan los operadores aritméticos de la suma y la resta, de tal
manera que puedan operar datos de tipo Vector.
#include <iostream>
using namespace std;
class Vector
{ private:
float CoordX;
float CoordY;
// Coordenada en eje x del vector
// Coordenada en eje y del vector
public:
Vector (float Va1 = 0, float Val2 =0); //constructor predeterminado
~Vector(){ };
//destructor
void ImprimeVector ();
//Muestra el vector
// Funciones para sobrecarga de operadores
Vector operator + (Vector Vec);
//Sobrecarga del operador "+" para realizar la
//suma de vectores
Vector operator - (Vector Vec);
//Sobrecarga del operador "-" para realizar la
//resta de vectores
};
/* Método constructor con parámetros predeterminados; a los cuales, si no se les
especifican otros valores, se les asignará 0 */
Programación II. Guía 7 9
Vector :: Vector(float Val1, float Val2)
{ CoordX = Val1;
CoordY = Val2;
}
// Método que imprime los valores de los atributos del vector
void Vector :: ImprimeVector( )
{ cout << "La componente en X del vector es: " << CoordX << endl;
cout << "La componente en Y del vector es: " << CoordY << endl;
}
/* Método en el cual se sobrecarga el operador "+"; por lo tanto se podrá utilizar para la
suma aritmética, como para suma de
vectores. Lo anterior da como resultado un objeto de tipo Vector */
Vector Vector :: operator + (Vector Vec)
{
return Vector(CoordX + Vec.CoordX, CoordY + Vec.CoordY);
}
/* Método en el cual se sobrecarga el operador "-"; por lo tanto se podrá utilizar para la
resta aritmética, como para resta de
vectores. Lo anterior da como resultado un objeto de tipo Vector */
Vector Vector :: operator - (Vector Vec)
{
return Vector(CoordX - Vec.CoordX, CoordY - Vec.CoordY);
}
int main()
{
system("cls");
Vector Vec1(3,1), Vec2(1,2), Vec3;
//Creamos los objetos de tipo Vector
// Se invoca al operador "+" sobrecargado, es decir, se realiza la suma de vectores
Vec3 = Vec1 + Vec2;
// Mostramos el vector resultante
cout << endl << endl << "Los datos del vector resultante de la suma de vectores son: "
<< endl;
Vec3.ImprimeVector();
// Se invoca al operador "-" sobrecargado, es decir, se realiza la resta de vectores
Vec3 = Vec1 - Vec2;
// Mostramos el vector resultante
cout << endl << endl << "Los datos del vector resultante de la resta de vectores son: "
<< endl;
Vec3.ImprimeVector();
system("pause>nul");
return 0;
}
10 Programación II, Guía 7
Análisis de Resultados
Ejercicio 1:
Modifique el código del ejemplo No. 2, de tal manera que la solución se maneje a través de un
menú que contenga las siguientes opciones:
a) Crear los objetos de tipo vector, solicitando los datos al usuario.
b) Realizar la suma de vectores.
c) Realizar la resta de vectores.
d) Realizar el producto escalar de vectores.
e) Salir de la aplicación.
El programa debe estar debidamente comentado.
Ejercicio 2:
Tomar el código del ejemplo No. 1 como referencia y realizar los cambios que sean necesarios
para crear un programa que provea la funcionalidad necesaria para trabajar con cadenas de
caracteres.
La funcionalidad debe implementarse con un menú con las siguientes opciones:
Opción de menú 1: Ingresar las cadenas de caracteres (como mínimo dos).
Opción de menú 2: Concatenar cadenas.
Opción de menú 3: Comparación de cadenas de caracteres. Considerar la sobrecarga de los
operadores ==, <, >, !=
Opción de menú 4: Determinar si una cadena está vacía. Considerar la sobrecarga del
operador “ ! “
Opción de menú 5: Acceder a un carácter individual en una cadena, es decir, realizar una
Opción de menú 6: Determinar la longitud de una cadena.
Opción de menú 7: Salir del programa.
El menú deberá estar siempre activo, en la misma posición en pantalla, hasta que el usuario
seleccione la opción salir.
El programa debe estar debidamente comentado.
Se sugiere utilizar la declaración de la clase Cadena mostrada a continuación:
Programación II. Guía 7 11
class Cadena
{
private:
int longitud;
// longitud de la cadena
char *ptr;
// Puntero a la cadena de caracteres
public:
Cadena (char []= "");
//constructor predeterminado
Cadena (Cadena &);
//constructor por copia
~Cadena();
//destructor
int long_cadena (void);
//devuelve longitud de la cadena
// Funciones para sobrecarga de operadores
bool operator == (Cadena &);
//prueba si s1 = s2
bool operator != (Cadena &);
//prueba si s1 != s2
bool operator ! ( );
//prueba si Cadena esta vacía
bool operator < (Cadena &);
//prueba si s1 < s2
bool operator > (Cadena &);
//prueba si s1 > s2
Cadena & operator + (Cadena &);
//concatenación
char operator[] (int);
//operador de subíndice
/* Sobrecarga de los operadores de manejo de flujos de entrada ">>" y de flujos de salida
"<<" */
friend ostream & operator<< (ostream &, Cadena &);
friend istream & operator>> (istream &, Cadena &);
};
12 Programación II, Guía 7
Hoja de cotejo:
Guía 7: Sobrecarga de Operadores.
Alumno:
Máquina No:
Docente:
GL:
7
Fecha:
EVALUACIÓN
%
CONOCIMIENTO
Del 20
al 30%
APLICACIÓN
DEL
CONOCIMIENTO
Del 40%
al 60%
1-4
5-7
8-10
Conocimiento
deficiente de
los fundamentos
teóricos
Conocimiento
y explicación
incompleta de
los
fundamentos
teóricos
Conocimiento
completo y
explicación
clara de los
fundamentos
teóricos
No tiene
actitud
proactiva.
Actitud
propositiva y
con
propuestas no
aplicables al
contenido de
la guía.
Tiene actitud
proactiva y
sus
propuestas
son
concretas.
ACTITUD
Del 15%
al 30%
TOTAL
100%
Nota
Descargar