Tema 2. Programación basada en objetosbadenas/IG17-2010-11/archivos/Tema2/Tema_2.pdf2.4. Objetos...

Post on 27-Apr-2020

4 views 0 download

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;

};