Tema 2. Programación basada en objetosbadenas/IG17-2010-11/archivos/Tema2/Tema_2.pdf2.4. Objetos...
Transcript of Tema 2. Programación basada en objetosbadenas/IG17-2010-11/archivos/Tema2/Tema_2.pdf2.4. Objetos...
Tema 2.Programación basada en objetos
Programación AvanzadaIngeniería Técnica en
Informática de GestiónJorge Badenas
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 2
2.1. Objetivos
Estudiar los conceptos de clase y objeto, y su implementación mediante el lenguaje C++.
Constructores y destructores.
Sobrecarga de operadores.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 3
2.2. Encapsulación de los datos
Encapsulación de los datos
ListinTelefonico
construirListininsertarTelefono
buscarTelefono
destruirListin
main
insercion
busqueda
cap
Programa
Interfaz
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 4
2.2. Encapsulación de los datos
El interfaz amortigua los efectos de los cambios internos de la estructura. Si no es preciso cambiar el
interfaz, los cambios no afectarán al programa.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 5
2.3 Características beneficiosas Mayor abstracciónMayor abstracción. Entidades de
más alto nivel. ModularidadModularidad. Agrupación de
estructuras de datos con las funciones que facilitan su manipulación.
Ocultación de la informaciónOcultación de la información. Para usar algo no es preciso saber cómo está hecho.
Encapsulación de los datosEncapsulación de los datos. El acceso a los datos se hace a través de un interfaz.
La encapsulación es la piedra angular que hace que las otras tres se cumplan.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 6
2.4. Objetos Necesitamos un mecanismo en los
lenguajes de programación que obligue a los programas a manejar los datos a través de la interfaz.
Los objetosobjetos son ese mecanismo que permite la encapsulación.
construirListininsertarTelefono
buscarTelefono
destruirListin
main
insercion
busqueda
cap
Programa
InterfazAccederdirectamentea los datos
ObjetoError de
compilación
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 7
2.5. Objetos y clases Un objeto es una instancia de una
claseclase. Una clase contiene dos tipos de
elementos: Datos Funciones que manejan los datos.
Dos tipos de elementos en una clase según el tipo de acceso: Privados Públicos
La interfaz de la clase lo forman las funciones públicas.
El resto de las funciones del programa que no pertenecen a la clase están obligadasobligadas a usar los datos a través de la interfaz.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 8
2.6 Transformando un Tipo de Dato en una Clase
struct Hora {int minutos;int horas;
};
void ponerEnHora( Hora& oh, int h, int m ) {oh.minutos = m;oh.horas = h;if( m>59 )
normalizar( oh );}
void normalizar( Hora& oh ) {oh.horas += oh.minutos / 60;oh.minutos = oh.minutos % 60;
}
void mostrarHora( const Hora &oh ) {cout<<oh.horas<<“:”<<oh.minutos;
}
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 9
2.6 Transformando un Tipo de Dato en una Clase
class Hora {public:void ponerEnHora( int h, int m);void mostrar( );private:int horas;int minutos;void normalizar( );
}; Para definir una clase se pueden
usar dos palabras clave: class struct (elementos públicos)
Los datos serán privados. Las funciones que permitían el
manejo de la estructura pasarán a pertenecer a la clase.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 10
2.6.1 Miembros de una clase. Las funciones y datos que pertenecen a
la clase reciben el nombre de miembros de la clasemiembros de la clase.
Métodos Funciones Atributos Datos
Los miembros privados son inaccesibles desde las funciones que no pertenecen a la clase (EncapsulaciónEncapsulación).
Las funciones públicas son la interfazinterfazde la clase.
Los datos de una clase son equivalentes a los campos de un tipo de dato structstruct de CC.
Las funciones de una clase están incrustadas en ella, por lo tanto no necesitan recibir el objeto, YA LO YA LO TIENENTIENEN.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 11
2.6.2. Declaración y uso de las clases// Sin clasesint main( ) {
Hora h;ponerEnHora( h, 6, 50 );mostrar( h );normalizar( h );h.minutos = 80;//Contenido incorrectoreturn 0;
}
// Con clasesint main( ) {
Hora h;h.ponerEnHora( 6, 50 );h.mostrar( );h.normalizar( ); // ERRORh.minutos = 80; // ERRORreturn 0;
}
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 12
2.6.3. Definición de funciones miembro
void Hora::mostrar( ) {cout<< horas << “:” <<minutos;
}
void Hora::normalizar( ) {horas += minutos / 60;minutos = minutos % 60;
}
void Hora::ponerEnHora( int h, int m ) {minutos = m;horas = h;if( m>59 )
normalizar( );}
Se debe poner el nombre de la clase
Cuando estoy en la clase se
sobreentiende que hablo de
Hora::minutos
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 13
Convertir en una clase:/* Archivo /* Archivo Cuenta.hCuenta.h */*/
struct Cuenta{char titular[30];int numero;float saldo;
};void asignarSaldo ( Cuenta &, float = 0.0);void inicializar ( Cuenta &, char *, int ,
float = 0.0);/*Archivo Cuenta.cpp *//*Archivo Cuenta.cpp */
#include <iostream>using namespace std;##includeinclude ““Cuenta.hCuenta.h””
void asignarSaldo (Cuenta &c, float s) {if (s<0.0) { cerr<<"SALDO NEGATIVO";
s=0.0;}c.saldo=s;
}
void inicializar (Cuenta &c, char *t, int n, float s) {
strcpy (c.titular, t);c.numero=n;asignarSaldoCuenta (c, s);
}
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 14
…viene de la página anterior
/* Archivo Principal.cpp *//* Archivo Principal.cpp */
int main ( ) {Cuenta c1, c2;
inicializar (c1, "Luis López", 35006);inicializar(c2, "Jesús García", 35007,
1000);asignarSaldo (c1, 500.0);asignarSaldo ( c2 );return 0;
}
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 15
2.7. Funciones inline
Si una función es breve, se puede escribir su código dentro de la estructura class.
Entonces es una función inline.
class Hora {public:…int leerMinutos( ) { return minutos; }int leerHoras( ) { return horas; }…
};
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 16
2.8. Funciones const
Cuando una función no modifica al objeto propietario de la función es conveniente definirla como const.
class Hora {public:…int leerMinutos( ) const { return minutos; }int leerHoras( ) const { return horas; }…
};
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 17
2.9. Constructores ConstructorConstructor: Función que se
ejecuta automáticamente al crearse un objeto.
Propósito: Inicializar el objeto. Características: Su nombre es el de la clase. No devuelve nada. Puede haber varios, por ejemplo:
Uno sin parámetros: por defecto. Uno con un parámetro de la misma
clase: copia. Los dos anteriores, el compilador
los proporciona de forma implícita: Si declaro un constructor, pierdo el
implícito por defecto. Cualquiera de los dos puedo declararlo
para redefinirlo a mi gusto. Crear un objeto siempre supone
usar un constructor... y ha de decidirse cuál en cada caso.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 18
2.10. Destructores DestructorDestructor: Función que se
ejecuta automáticamente cuando un objeto deja de existir.
Propósito: Liberar los recursos que el objeto tuviera ocupados (memoria, ficheros, etc.).
class Lista {Nodo *cap;
public:~Lista( );
…};Lista::~Lista( ) {
Nodo *nt;while( cap != NULL ) {
nt = cap; cap = cap->sig; delete nt;
}}
Si no, hay un destructor implícito.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 19
2.11. El constructor copia Construye un objeto a partir de otro
de la misma clase. Hay uno implícito que copia
miembro a miembro. Si el constructor copia implícito no
es adecuado, debo reescribirlo. Dada una clase A, el constructor
copia se define como:class A {…
A( const A&origen);…}; Se trata de inicializar un objeto de
la clase A a partir de otro objeto de la clase A (origen).
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 20
2.12. Constructores y arrays. Los objetos de un array también se
construyen y se destruyen. Paso de parámetros a constructores
de arrays:
class Complejo {
public:
Complejo(float r=0.0, float i=0.0) {...}
...
};
int main() {
Complejo vc1[10];
Complejo vc2[3]= {1.0, 2.0, 3.0};
Complejo vc3[2]= {Complejo(1.0, 1.0), Complejo(2.0, 2.0)};
Complejo * pc, * pvc;
pc = new Complejo(1.1, 2.2);
pvc = new Complejo[5];
...
delete pc; delete[] pvc;
...
}
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 21
2.13. Funciones y clases amigas (friend) Una función amiga es una función qué
aunque no pertenece a una clase recibe el privilegio de poder acceder a la parte privada.
Para hacer una función amiga de una clase se ha de poner en la clase la palabra friend seguida del prototipo de la función.
Si se quiere que todas las funciones de una clase A puedan acceder a la parte privada de una clase B, se definirá la clase A como amiga de B.
class B {…friend class A;…};
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 22
2.14. this this es la dirección (inmutable) del
objeto sobre el que se está ejecutando una función miembro.
class A {A* direccion( ) { return this; }A objeto( ) { return *this; }A& objetoReferencia( ) { return *this; }void escrX( int v) { this->x = v; }
private:int x;
};… // En alguna funciónA a, b;A* pa = a.direccion( ); // pa = &aA* pb = b.direccion( ); // pb = &bb = a.objeto( ); // b=aa.objetoReferencia( ).escrX( 10 );// Lo mismo que a.escrX( 10 )
2.15. Sobrecarga de operadores La sobrecarga de operadores
consiste en asociar funciones a operadores. El operador es una abreviatura que
implica la ejecución de una función. Podemos sobrecargar los
operadores que existen, pero no podemos: Inventar operadores nuevos. Cambiar el número de operandos
que requiere un operador. Sobrecargar el operador + consiste
en escribir una función llamada operator+. Lo mismo para el resto de operadores.
23Programación Avanzada - Ingeniería Técnica en Informática de Gestión
2.15 Sobrecarga de operadores
class Racional {
public:
Racional( int n, int d = 1):
num( n ), den( d ) { }
Racional( ) { }
private:
int num; // Numerador
int den; // Denominador
};
Queremos que funcione:Racional a, b, c;
a = b + c;
24Programación Avanzada - Ingeniería Técnica en Informática de Gestión
2.15 Sobrecarga de operadores En a = b + c hay dos operadores:
b + c Racional + Racional
a=Resultado(b+c) Rac = Rac
Para sobrecargar b + c debemos escribir una función llamada operator+.
operator+ puede tener dos formas: Miembro de la clase Racional:
b.operator+( c )
No miembro:operator+( b, c )
Podemos escoger la forma que queramos.
Según la que elijamos tendremos distinto número de parámetros.
25Programación Avanzada - Ingeniería Técnica en Informática de Gestión
2.15 Sobrecarga de operadores
¿Qué debe devolver b + c?Racional + Racional Racional
¿Qué debe hacer b + c? Sumar b más c y devolver el
resultado ¿Modificar a los objetos b o c?
No es lo que ocurre con los tipos de datos del lenguaje (int, float, etc.)
26Programación Avanzada - Ingeniería Técnica en Informática de Gestión
2.15 Sobrecarga de operadores Como no miembro, la función sería:
Racional operator+( const Racional& b, const Racional& c ) {
Racional tmp;
tmp.num = b.num*c.den + b.den*c.num;
tmp.den = b.den*c.den;
return tmp;
}
Si accede a miembros privados desde una función no miembro, la función debe ser friend:
class Racional {
friend Racional operator+(const Racional& b, const Racional& c );
… // Resto del class
};
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 27
2.15 Sobrecarga de operadores
Falta el operator=Racional = Racional
No es necesario implementarlo, porque todas las clases tienen una versión implícita de ese operador.
Racional& operator=(const Racional&);
Realiza la asignación de cada uno de los datos miembros de la clase.
Lo deberemos redefinir cuando necesitemos que este operador haga algo diferente.
Pregunta: ¿funcionará?:a = b + c + d;
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 28
2.16. Racional += Racional Haremos que la función sea
miembro de la clase Racional a += b a.operator+=( b )
Un operador no es normal que retorne void, así que haremos que devuelva Racional.
La función debe modificar el primer operando racional.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 29
class Racional {Racional& operator+=( const Racional& );
…};
Racional& Racional::operator+=( const Racional& b ) {
num = num * b.den + den * b.num;den *= b.den;return *this;
}
2.17. Racional == Racional ¿Qué debe devolver a == b? bool. Mejor como función externa:
a == b operator==(a, b)
class Racional {
...
friend bool operator==(const Racional&,
const Racional&);
...
};
...
bool operator==(const Racional& a,
const Racional& b) {
return a.num/a.den == b.num/b.den;
}
Problema con los tipos de datos: 4/5 == 1/3 ¿true?
¿Sobrecargamos también !=?
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 30
2.18. -Racional Uso:Racional q, p;
p = -q; // p = q.operator-( );
Declaración:class Racional {
Racional operator-( ) const;
…
};
Código de la función:// Versión 1
Racional Racional::operator-( ) const {
Racional aux;
aux.num = -num;
aux.den = den;
return aux;
}
// Versión 2
Racional Racional::operator-( ) const {
return Racional( -num, den );
}
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 31
2.19. Operaciones entre clases distintas
Si se quiere poder sumarComplejo y Racional con el operador +, hay dos opciones:
Sobrecargar operator+ paraComplejo y Racional.
Suponiendo que ya se dispone de la suma de complejos, especificar la conversión de Racional enComplejo. De esta forma, enComplejo + Racional:
1. Se convierte automáticamente elRacional en un Complejo.
2. Se efectúa la suma con la sobrecarga del operator+ para dos complejos.
2.20. Complejo + RacionalComplejo c1, c2;
Racional q;
c1 = c2 + q;
Declaración en las clases:class Complejo {
Complejo operator+( const Racional&)const;
…
};
class Racional {
friend Complejo Complejo::operator+(
const Racional& ) const;
…
};
Código de la función:Complejo Complejo::operator+(
const Racional& q)const {
float rac =
static_cast<float>( q.num ) / q.den ;
return Complejo( real + rac,imaginaria );
}
2.21. Racional + ComplejoComplejo c1, c2;
Racional q;
c1 = q + c2;
Declaración en las clases:class Complejo {
friend Complejo operator+( const Racional&, const Complejo& );
…
};
class Racional {
friend Complejo operator+(const Racional&,
const Complejo& );…
};
Código de la función:
Complejo operator+( const Racional& q,
const Complejo& c) {
float rac =
static_cast<float>( q.num ) / q.den ;
return Complejo(c.real+rac,c.imaginaria );
}
2.22. Conversión mediante constructores El constructor permite convertir un
objeto a otra clase diferente.class Complejo {
public:
Complejo(const Racional&);
...
friend Complejo operator+(const Complejo&, const Complejo&);
private:
float real, imaginaria;
};
Complejo::Complejo(const Racional& q) {
real = static_cast<float>(q.num) / q.den;
imaginaria = 0.0;
}
Se puede evitar que se produzcan conversiones implícitas (coerciones), poniendo la palabra explicit
delante del constructor.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 35
2.22. Conversión mediante constructores
Racional r;
Complejo c1, c2;
c1 = c2 + r;
C1 = r + c2;
El objeto r primero se convierte en un Complejo mediante el constructor, después se llama a la sobrecarga del operador + que suma dos complejos.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 36
2.22 ++Racional y Racional++class Racional {
Racional& operator++( );
Racional operator++( int );
…
};
Racional& Racional::operator++( ) {
num += den;
return *this;
}
Racional Racional::operator++( int ) {
Racional tmp = *this;
num += den;
return tmp;
}
El parámetro entero es artificial, sólo sirve para diferenciar el operador posfijo del prefijo.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 37
2.23. Operadores de E/S Se trata de sobrecargar los
operadores >> y <<.
Racional q;
cout << “Dame un racional... ”;
cin >> q;
cout << “q vale ” << q << endl;
cout pertenece a la clase ostream, mientras que cin pertenece a istream.
Estos operadores no pueden ser funciones miembro, porque el operando de la izquierda no es el de mi clase.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 38
2.23. Operadores de E/S
El operador de salida es <<:Racional q(2, 3);
cout << q; // operator<<(cout, q);
Se debe devolver por referencia el operando izquierdo (un ostream) para poder ordenar más salidas en la misma expresión:cout << q1 << “ y ” << q2 << endl;
Posible implementación:ostream& operator<<(ostream& os,
const Racional& q) {
os << q.num << ‘/’ << q.den;
return os;
}
Si se accede a datos privados, la función tendrá que ser friend.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 39
2.23. Operadores de E/S
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 40
El operador de entrada es >>:Racional q;
cin >> q; // operator>>(cin, q);
El formato que lee operator>>
debe ser similar al que escribeoperator<<.
Posible implementación:istream& operator>>(istream& is,
Racional& q) {
char c; // para leer ‘/’
is >> q.num >> c >> q.den;
return is;
}
Consideraciones análogas al caso anterior, pero: istream en vez de ostream.
Operando derecho, por referencia no const.
2.24. El operador = Dada una clase C, su cabecera es:
C& C::operator=(const C&);
Todas las clases disponen de un operator= implícito, que debe redefinirse si no es adecuado.
El operator= implícito asigna los datos de un objeto al otro, miembro a miembro.
No se debe confundir el constructor copia con el operator=. Al constructor sólo se le puede llamar cuando se está inicializando un objeto que es nuevo. Pero puede ser útil definirlo a partir
de la asignación, hecha sobre *this. Es importante prever casos como a=a; (autoasignación).
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 41
2.25. Operador de indexación Para acceder a un elemento de un
objeto contenedor mediante su índice (no siempre int):obj[ind] obj.operator[](ind)
// acceso al elemento ind de obj
Por ejemplo, para que funcione:VectorFloat v(10); // Diez flotantes
float x;...
x = v[5]; // Lectura
v[6] = x; // Escritura
Para poder escribir, operator[] no puede devolver una copia del elemento, sino una referencia a él.
Para poder leer incluso si el contenedor es const, necesitamos una versión que devuelva copia o referencia const.
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 42
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 43
class VectorFloat{
public:
// Para lectura y escritura (Op1)
float& operator[](int i)
{ return elementos[i]; }
// Para sólo lectura (Op2)
float operator[](int i) const
{ return elementos[i]; }
...
private:
int nelems; // Número de elementos
int *elementos;
};
void raro(VectorFloat& vvble,
const VectorFloat& vcte) {
float x;
...
x = vvble[0]; // Versión Op1
x += vcte[1]; // Versión Op2
vvble[2] = 2*x; // Versión Op1
}
2.25. Operador de indexación
Programación Avanzada - Ingeniería Técnica en Informática de Gestión 44
2.26. Operador de llamada Para utilizar un objeto como si fuera
una función:obj(arg1,... argn)
obj.operator()(arg1,... argn)
Puede definirse para el número de argumentos que se desee.
Por ejemplo, para acceso a elementos de una matriz:class MatrizFloat{
public:
float& operator()(int i, int j)
{ return elementos[i*ncols+j]; }
float operator()(int i, int j) const
{ return elementos[i*ncols+j]; }
...
private:
int nfils, ncols;
int *elementos;
};