Académique Documents
Professionnel Documents
Culture Documents
POLIMORFISMO
Cristina Cachero, Pedro J. Ponce de Len
4 Sesiones (6 horas) Versin 0.9
Comprender el concepto de polimorfismo Conocer y saber utilizar los diferentes tipos de polimorfismo. Comprender el concepto de enlazado esttico y dinmico en los lenguajes OO. Comprender la relacin entre polimorfismo y herencia en los lenguajes fuertemente tipados. Apreciar la manera en que el polimorfismo hace que los sistemas sean extensibles y mantenibles.
Curso 07-08
Indice
1. Motivacin y conceptos previos
Signatura y mbito Tiempo de enlace Denicin Tipos de polimorsmo Sobrecarga basada en mbito Sobrecarga basada en signatura de tipo Alternativas a la sobrecarga Redenicin Shadowing Sobrescritura La variable receptora Downcasting Polimorsmo puro Funciones genricas en C++ Plantillas de clase en C++ Herencia en clases genricas
3
2. Polimorsmo y reutilizacin
3. Sobrecarga
5. Variables polimrcas
6. Genericidad
Curso 07-08
1. Motivacin
Objetivo de la POO
El polimorfismo es el modo en que los lenguajes OO implementan el concepto de polisemia del mundo real:
Curso 07-08
Descripcin de los tipos de sus argumentos, su orden y el tipo devuelto por el mtodo.
Notacin: <argumentos> <tipo devuelto> Omitimos el nombre del mtodo, el de la clase a la que pertenece (el tipo del receptor)
Ejemplos
double power (double base, int exp) double*int double bool Casilla::setPieza(Pieza& p) Pieza bool
Curso 07-08
mbito de un nombre:
Porcin del programa en la cual un nombre puede ser utilizado de una determinada manera. Ejemplo:
La variable base slo puede ser utilizada dentro del mtodo power
class A { int x,y; public: void f() { // mbitos activos: // GLOBAL // CLASE (atribs. de clase y de instancia) // METODO (argumentos, var. locales) if () { string s; // LOCAL (var. locales) } Curso 07-08 }
Momento en el que se identifica el fragmento de cdigo a ejecutar asociado a un mensaje (llamada a mtodo) o el objeto concreto asociado a una variable.
Tiempo de Compilacin: Enlace esttico (early binding) EFICIENCIA Tiempo de Ejecucin: Enlace dinmico (late binding): FLEXIBILIDAD
Aplicable a:
OBJETOS: Con enlace esttico el tipo de objeto que contiene una variable se determina en tiempo de compilacin. Con enlace dinmico el tipo de objeto al que hace referencia una variable no est predefinido, por lo que el sistema gestionar la variable en funcin de la naturaleza real del objeto que referencie en cada momento. Lenguajes como Smalltalk siempre utilizan enlace dinmico con variables C++ slo permite enlace dinmico con variables cuando stos son punteros, y slo dentro de jerarquas de herencia. OPERACIONES: Con enlace esttico la eleccin de qu mtodo ser el encargado de responder a un mensaje se realiza en tiempo de compilacin, en funcin del tipo que tena el objeto destino de la llamada en tiempo de compilacin. Con enlace dinmico la eleccin de qu mtodo ser el encargado de responder a un mensaje se realiza en tiempo de ejecucin, en funcin del tipo correspondiente al objeto que referencia la variable mediante la que se invoca al mtodo en el instante actual.
7
Curso 07-08
El tipo de lenguaje utilizado (fuertemente o dbilmente tipado) determina su soporte al enlace dinmico:
Lenguajes Procedimentales: no soportan enlace dinmico: el tipo de toda expresin (identificador o fragmento de cdigo) se conoce en tiempo de compilacin. LOO: slo soportan enlace dinmico dentro de la jerarqua de tipos a la que pertenece toda expresin (identificador o fragmento de cdigo) establecida en tiempo de compilacin.
S soportan enlace dinmico: el enlace entre variables y tipo (sin restricciones) se efecta en tiempo de ejecucin (variables se compilan sin asignarles tipo concreto).
Curso 07-08
Indice
1. Motivacin y conceptos previos
Signatura y mbito Tiempo de enlace Denicin Tipos de polimorsmo Sobrecarga basada en mbito Sobrecarga basada en signatura de tipo Alternativas a la sobrecarga Redenicin Shadowing Sobrescritura La variable receptora Downcasting Polimorsmo puro Funciones genricas en C++ Plantillas de clase en C++ Herencia en clases genricas
2.
Polimorsmo y reutilizacin
3.
Sobrecarga
4.
5.
Variables polimrcas
6.
Genericidad
Curso 07-08
2. Polimorfismo
Definicin
El polimorfismo nos permite programar de manera general en lugar de programar de manera especfica. Hay cuatro tcnicas, cada una de las cuales permite una forma distinta de reutilizacin de software, que facilita a su vez el desarrollo rpido, la confianza y la facilidad de uso y mantenimiento.
Curso 07-08
10
Tipos de polimorfismo
Sobrecarga (Overloading, Polimorfismo ad-hoc): un solo nombre de mtodo y muchas implementaciones distintas.
Las funciones sobrecargadas normalmente se distinguen en tiempo de compilacin por tener distintos parmetros de entrada y/o salida.
Sobreescritura (Overriding, Polimorfismo de inclusin): Tipo especial de sobrecarga que ocurre dentro de relaciones de herencia.
En este caso la signatura es la misma (refinamiento o reemplazo del mtodo del padre) pero los mtodos se encuentran en dos clases distintas relacionadas mediante herencia.
Variables polimrficas (Polimorfismo de asignacin): variable que se declara como de un tipo pero que referencia en realidad un valor de un tipo distinto.
Cuando una variable polimrfica se utiliza como argumento, la funcin resultante se dice que exhibe un polimorfismo puro.
Genericidad (plantillas o templates): forma de crear herramientas de propsito general (clases, mtodos) y especializarlas para situaciones especficas.
11
Curso 07-08
Tipos de polimorfismo
Sobrecarga
Factura::imprimir() Factura::imprimir(int numCopias) ListaCompra::imprimir()
Sobreescritura
Cuenta::abonarInteres() CuentaJoven::abonarInteres()
Variables polimrficas
Cuenta *pc=new CuentaJoven();
Genericidad
Lista<Cliente> Lista<Articulo> Lista<Alumno> Lista<Habitacion>
Curso 07-08
12
Indice
1. Motivacin y conceptos previos
Signatura y mbito Tiempo de enlace Denicin Tipos de polimorsmo Sobrecarga basada en mbito Sobrecarga basada en signatura de tipo Alternativas a la sobrecarga Redenicin Shadowing Sobrescritura La variable receptora Downcasting Polimorsmo puro Funciones genricas en C++ Plantillas de clase en C++ Herencia en clases genricas
2.
Polimorsmo y reutilizacin
3.
Sobrecarga
4.
5.
Variables polimrcas
6.
Genericidad
Curso 07-08
13
Un mismo nombre de mensaje asociado a varias implementaciones La sobrecarga se realiza en tiempo de compilacin (enlace esttico) en funcin de la signatura completa del mensaje. Dos tipos de sobrecarga:
Basada en mbito: Mtodos con diferentes mbitos de definicin, independientemente de sus signaturas de tipo. Permitido en todos los lenguajes OO.
Un mismo mtodo puede ser utilizado en dos o ms clases. P. ej. Sobrecarga de operadores como funciones miembro.
Basada en signatura:Mtodos con diferentes signaturas de tipo en el mismo mbito de definicin. No permitido en todos los lenguajes OO.
P. ej. Cualquier conjunto de funciones no miembro (en el mbito de definicin global) que comparten nombre. Dos o ms mtodos en la misma clase pueden tener el mismo nombre siempre que tengan distinta signatura de tipos.
14
Curso 07-08
Distintos mbitos implican que el mismo nombre de mtodo puede aparecer en ellos sin ambigedad ni prdida de precisin. La sobrecarga por mbito no requiere que las funciones asociadas con un nombre sobrecargado tengan ninguna similitud semntica, ni la misma signatura de tipo. Ejemplos
Carta
Baraja
+dibuja(int nMontones=1)
Pers Profesor
+getNombre() Curso 07-08
+dibuja()
Alumno
+getNombre()
Maratn
+getDistancia()
Lnea
+getDistancia()
15
Mtodos en el mismo mbito pueden compartir el mismo nombre siempre que difieran en nmero, orden y, en lenguajes con tipado esttico, el tipo de los argumentos que requieren.
Este estilo ocurre en muchos lenguajes funcionales, en algunos imperativos (e.g. ADA) y en lenguajes OO como C++, C#, Java, Delphi Pascal o CLOS C++ permite esta sobrecarga de manera implcita siempre que la seleccin del mtodo requerido por el usuario pueda establecerse de manera no ambigua en tiempo de compilacin.
Esto implica que la signatura no puede distinguirse slo por el tipo de retorno
Suma
+add(int a) +add(int a, int b) +add(int a, int b, int c)
Curso 07-08
16
Este modo de sobrecarga en tiempo de compilacin puede dar lugar a resultados inesperados: class Padre{}; class Hijo: public Padre{}; void Test (Padre *p) {cout << padre;}; void Test (Hijo *h) {cout << hijo;}; //ppio sust. int main(){ Padre *obj; int tipo;cin>>tipo; if (tipo==1) obj=new Padre(); else obj=new Hijo(); //ppio de sustitucin Test (obj); //a quin invoco? }
Curso 07-08
17
Permiten sobrecarga de mtodos y operadores: C++ Permiten sobrecarga de mtodos pero no de operadores: Java, Python, Perl Permiten sobrecarga de operadores pero no de mtodos: Eiffel
Curso 07-08
18
Dentro de la sobrecarga basada en signaturas de tipo, tiene especial relevancia la sobrecarga de operadores
Uso: Utilizar operadores tradicionales con tipos definidos por el usuario.
Hay que ser cuidadoso con su uso, pues puede dificultar la comprensin del cdigo si se utilizan en un sentido distinto al habitual.
Forma de sobrecargar un operador @: <tipo devuelto> operator@(<args>) Para utilizar un operador con un objeto de tipo definido por usuario, ste debe ser sobrecargado.
El operador direccin (&) por defecto devuelve la direccin del objeto. El operador asignacin por defecto asigna campo a campo.
Curso 07-08
19
Precedencia (qu operador se evala antes) Asociatividad a=b=c a=(b=c) Aridad (operadores binarios para que acten como unarios o viceversa)
No se puede crear un nuevo operador No se pueden sobrecargar operadores para tipos predefinidos.
Se pueden sobrecargar todos los operadores definidos en C++ como unarios y binarios excepto ".", ".*", "::, sizeof. "?: es el nico operador ternario definido en C++, y no puede ser sobrecargado
Curso 07-08
20
Como funcin miembro: el operando de la izquierda (en un operador binario) debe ser un objeto (o referencia a un objeto) de la clase:
Complejo Complejo::operator+(const Complejo&) Complejo c1(1,2), c2(2,-1); c1+c2; // c1.operator+(c2); c1+c2+c3; // c1.operator+(c2).operator+(c3)
Curso 07-08
21
2. Por claridad
Complejo operator+(const Complejo&, const Complejo&);
Curso 07-08
22
En C++, los operadores "=", "[]", "->", "()", "new" y "delete", slo pueden ser sobrecargados cuando se definen como miembros de una clase.
Si un operador tiene formatos unarios y binarios (+,&), ambos formatos pueden ser sobrecargados.
Curso 07-08
23
Sobrecarga de operadores unarios: Los operadores unarios pueden ser sobrecargados sin argumentos o con un argumento Usualmente son implementados como funciones miembro.
<tipo> operator<operador>() ;
Ejemplo: Tiempo Tiempo::operator++() // PREINCREMENTO { minuto++; if (minuto >= 60) { minuto = minuto - 60; hora++; } return *this; }
24
class Tiempo{ public: Tiempo(int, int); void mostrar(); Tiempo operator++(); private: int hora; int minuto; };
Curso 07-08
Cul sera la salida de este programa? Sobrecarga del mismo modo el operador -- (predecremento y postdecremento)
Tiempo Tiempo::operator++(int x) { Tiempo aux(*this); minuto++; if (minuto >= 60){ minuto = minuto - 60; hora++; } return aux; } void main(){ Tiempo t1(17,9); t1.mostrar();//?? (t1++).mostrar();//?? t1.mostrar();//?? (++t1).mostrar();//?? t1.mostrar();//?? }
25
Curso 07-08
Se desea que el operador ! indique true si x e y son diferentes y false en caso contrario.
Curso 07-08 26
<tipo_devuelto> operator<operador>(<tipo>);
class Tiempo{ public: Tiempo(int h=0, int m=0) {hora=h; minuto=m;}; void mostrar(){ cout <<hora <<":"<<minuto<<endl; }; private: int hora; int minuto; };
Curso 07-08
Curso 07-08
28
Curso 07-08
29
Curso 07-08
30
Curso 07-08
31
Corolario:
Cuando nuestras clases tengan variables de instancia que sean punteros a memoria dinmica debemos sobrecargar siempre el operador de asignacin y el constructor de copia, ya que nunca sabemos cundo puede ser invocado sin que nos demos cuenta.
Curso 07-08
32
Se pide: Declara (.h) y define (.cpp) la sobrecarga del operador += para la clase TPunto. Haz lo mismo suponiendo que no podemos aadir funciones miembro a la clase.
Curso 07-08 33
La posibilidad de sobrecarga de los operadores << (salida) y >> (entrada) resuelve el problema tradicional de libreras de I/O pensadas para trabajar exclusivamente con tipos predefinidos (built-in) La abstraccin flujo de salida (ostream) representa una entidad que acepta una secuencia de caracteres. Esa entidad puede luego convertirse en un fichero, una ventana o una red. La abstraccin flujo de entrada (istream) representa una entidad que enva una secuencia de caracteres. Esa entidad puede luego convertirse en un teclado, un fichero o una red. La librera estndar proporciona una coleccin de definiciones sobrecargadas para el operador << y >>
ostream& operator << (ostream& dest, int source); ostream& operator << (ostream& dest, char source); ostream& operator << (ostream& dest, char * source); oper izqda oper dcha Ejemplo
cout << El resultado es << x << \n; cout << x << \n; cout << \n;
Curso 07-08
34
La extensin de esta librera para otros tipos de datos sigue el mismo patrn:
ostream& operator << (ostream& o, const <nuevoTipo>& t) istream& operator >> (istream& i, <nuevoTipo>&t) Para que esta funcin tenga acceso a la parte privada/protegida de t, deberemos definirla como friend de la clase <nuevoTipo>.
Ojo! En cualquier caso debe tratarse de una funcin no miembro, ya que el operador de la izquierda no es un objeto de la clase.
class Tiempo{ friend ostream &operator<<(ostream &,const Tiempo &); friend istream &operator>>(istream &,Tiempo &); public: private: int hora; int minuto; };
Curso 07-08 35
return (0); }
Curso 07-08 37
cin >> p1; cin >> p2; cout << p1 << "y" << p2 << endl; }
Curso 07-08
39
Curso 07-08
40
Ejemplo:
class Vector { public: Vector( int ne=1) { num = ne; pV = new int[ num]; }; ~Vector(){ delete [] pV; pV=NULL;}; int& operator[](int i) {return pV[ i];}; private: int *pV; // puntero al 1 elemento int num; // num de elementos };
Curso 07-08 41
Curso 07-08
42
Definid (.h) e implementad (.cpp) vuestra propia clase Vector de enteros con las siguientes caractersticas:
Vector
+ Vector(int capacidad) +~Vector +Vector (const Vector &v) +operator=(const Vector&v): Vector& +operator==(const Vector &v): bool <<const>> +operator!=(const Vector&v): bool <<const>> +operator[](const int indice) const int& << const>> //rvalue: debe controlar ndice fuera rango <<friend>> operator>>(Vector &v) <<friend>> operator<< (const Vector &v)
Curso 07-08
43
Modifica lo que sea necesario en la declaracin y/o definicin del operador asignacin para que controle los siguientes casos:
Si an no lo has hecho, redefine el constructor de copia en base a la definicin del operador = Modifica el cdigo asociado al operador [] para que pueda actuar de lvalue en expresiones del tipo
Vector v;v[3]=2;
Curso 07-08
44
Objetivo: Implementar una TablaAsociativa que contenga pares clave-valor (string-int), y permitir el acceso mediante la clave al valor correspondiente E.g. int v=mitabla[clave]
Ejemplo: Uso de una tabla Asociativa para guardar el nmero de veces que introduzco cada palabra
int main(){ char palabra[256]; TTablaAsoc t(512); for (register int i=0;i<10;i++){ cin>>palabra; t[palabra]++; } cout<<t<<endl; return (0); }
Curso 07-08 45
Curso 07-08
46
Las funciones con nmero variable de argumentos (polidicas) se encuentran en distintos lenguajes
Si el nmero mximo es conocido, en C++ y Delphy Pascal podemos acudir a la definicin de valores por defecto para parmetros opcionales
P. ej. int sum (int e1, int e2, int e3=0, int e4=0);
#include <stdarg.h> int sum (int numEle, ...){ //... indica nm variable de args va_list ap; //tipos predefinidos en stdarg.h int resp=0; va_start(ap, numEle); //inicializa lista con el num argumentos while (numEle>0){ resp += va_arg(ap,int); numEle--; } va_end(ap); return (resp); Curso 07-08 }
49
Alternativas a sobrecarga:
Coercin y Conversin
En algunas ocasiones la sobrecarga puede sustituirse por una operacin semnticamente diferente: La COERCIN
El principio de sustitucin en los LOO introduce adems una forma de coercin que no se encuentra en los lenguajes convencionales
Curso 07-08
50
Alternativas a sobrecarga:
Coercin y Conversin
Cuando el cambio en tipo es solicitado de manera explcita por el programador hablamos de CONVERSIN
El operador utilizado para solicitad esta conversin se denomina CAST Ejemplo: float x; int i; x= i + x; // COERCION x= ((double) i) + x; // CONVERSION Un cast puede cambiar la representacin interna de la variable (convertir un entero en un real, p.ej.) o cambiar el tipo sin cambiar la representacin (p.ej., convertir un puntero a hijo en un puntero a padre). Dentro de una clase C podemos definir el cast: De un tipo externo al tipo definido por la clase: implementacin de constructor con un solo parmetro del tipo desde el cual queremos convertir. Del tipo definido por la clase a otro tipo distinto en C++: implementacin de un operador de conversin.
Curso 07-08
51
Alternativas a sobrecarga:
Coercin y Conversin
Alternativas a sobrecarga:
Coercin y Conversin
Si adems deseamos realizar la conversin: Sera necesario aadir a la clase fraccin el operador:
operator double() { //SIN TIPO RETORNO return (numerador()/(double)denominador()); }; double d=f*3.14;
Obviamente, cuando la coercin (conversin implcita), la conversin (explcita) y la sustitucin de valores se combinan en una sola sentencia, el algoritmo que debe utilizar el compilador para resolver una funcin sobrecargada puede convertirse en bastante complejo.
Curso 07-08
53
Indice
1. Motivacin y conceptos previos
Signatura y mbito Tiempo de enlace Denicin Tipos de polimorsmo Sobrecarga basada en mbito Sobrecarga basada en signatura de tipo Alternativas a la sobrecarga Redenicin Shadowing Sobrescritura La variable receptora Downcasting Polimorsmo puro Funciones genricas en C++ Plantillas de clase en C++ Herencia en clases genricas
2.
Polimorsmo y reutilizacin
3.
Sobrecarga
4.
5.
Variables polimrcas
6.
Genericidad
Curso 07-08
54
Shadowing (refinamiento/reemplazo): las signaturas de tipo son las misma en clases padre e hijas, pero el mtodo a invocar se decide en tiempo de compilacin
Redefinicin: clase hija define un mtodo con el mismo nombre que el padre pero con distinta signatura de tipos.
Curso 07-08
55
Los diferentes significados que se encuentran en todos los mbitos actualmente activos se unen para formar una sola coleccin de mtodos. Cuando se encuentra un mbito en el que el nombre est definido, la coincidencia ms cerbcana en ese mbito ser la seleccionada para resolver la llamada.
class Padre{ public: void ejemplo(int a){cout<<Padre;}; }; class Hija: public Padre{ public: void ejemplo (int a, int b){cout<<Hija;}; }; int main(){ Hija h; h.ejemplo(3); // OK en Java //pero ERROR DE COMPILACIN EN C++ return (0); }
Curso 07-08
56
Decimos que un mtodo en una clase derivada sobreescribe un mtodo en la clase base si los dos mtodos tienen el mismo nombre, la misma signatura de tipos y enlace dinmico.
en clases relacionadas mediante jerarquas de herencia La signatura de tipos debe ser EXACTAMENTE la misma Los mtodos sobreescritos pueden suponer un reemplazo del comportamiento (mtodo independiente del del padre, igual que la sobrecarga) o un refinamiento (mtodo no independiente) La resolucin del mtodo a invocar se produce en tiempo de ejecucin (enlace dinmico o late-binding) en funcin del tipo dinmico del receptor del mensaje.
El tipo de cualquier otro argumento pasado junto con el mensaje sobreescrito generalmente no juega ningn papel en el mecanismo de seleccin del mtodo sobreescrito. Una variable del tipo del padre puede, por el principio de sustitucin, ser declarada como de tipo Padre pero contener en realidad un valor del tipo hijo. Cuando un mensaje que se corresponde con un mtodo sobreescrito se pasa a dicha variable, el mtodo que ser ejecutado es el proporcionado por el hijo, NO por el padre.
57
Curso 07-08
En algunos lenguajes (Java, Smalltalk) la simple existencia de un mtodo con el mismo nombre y signatura de tipos en clase base y derivada indica sobreescritura. En otros lenguajes (Object Pascal), la clase derivada debe indicar que sobreescribe un mtodo. Otros lenguajes (C#, Delphi Pascal) exigen que tanto la clase base como la derivada lo indiquen. En C++ es la clase base la que debe indicar explcitamente que un mtodo puede ser sobreescrito (aunque dicha marca no obliga a que lo sea)
Curso 07-08
58
Sobreescritura y mtodos diferidos (virtuales puros o abstractos) En los lenguajes fuertemente tipados, si queremos sobreescribir un mtodo en las clases hijas para poder invocarlo mediante una variable polimrfica, es necesario que dicho mtodo est definido en la clase padre. No obstante, es posible que dicha clase padre no pueda definir ningn comportamiento por carecer de la informacin necesaria. Solucin: mtodos diferidos o abstractos
};
class Circulo: public Forma{ public: void dibujar(){...} };
Los mtodos virtuales puros (de sobreescritura necesaria, y que implementan la especializacin) a menudo conviven con mtodos no sobreescribibles, base del reuso de cdigo.
59
Curso 07-08
Polimorfismo
Sobreescritura: la signatura de tipo para el mensaje es la misma en clase base y derivada, pero el mtodo se enlaza con la llamada en tiempo de ejecucin (en C++ el mtodo se declara como virtual en la clase padre). Shadowing: la signatura de tipo para el mensaje es la misma en clase base y derivada, pero el mtodo se enlaza en tiempo de compilacin (en funcin del tipo de la variable receptora). Redefinicin: La clase derivada define un mtodo con el mismo nombre que en la calse base y con distinta signatura de tipos.
60
Curso 07-08
Indice
1. Motivacin y conceptos previos
Signatura y mbito Tiempo de enlace Denicin Tipos de polimorsmo Sobrecarga basada en mbito Sobrecarga basada en signatura de tipo Alternativas a la sobrecarga Redenicin Shadowing Sobrescritura La variable receptora Downcasting Polimorsmo puro Funciones genricas en C++ Plantillas de clase en C++ Herencia en clases genricas
2.
Polimorsmo y reutilizacin
3.
Sobrecarga
4.
5.
Variables polimrcas
6.
Genericidad
Curso 07-08
61
Puede mantener valores de distintos tipos en distintos momentos de ejecucin del programa.
En un lenguaje dbilmente tipado todas las variables son potencialmente polimrficas En un lenguaje fuertemente tipado la variable polimrfica es la materializacin del principio de sustitucin.
Curso 07-08
62
Barco *b[10]; //array de punteros a Barco que en realidad //contiene punteros a las distintas clases derivadas
Variable polimrfica como receptor de mensaje this: en cada clase representa un objeto de un tipo distinto.
Especialmente potente cuando se combina con sobreescritura. class Barco{ public: virtual int getNumPiezas()=0; void colocaPieza(Pieza &p, Coordenada); bool colocaBarco(){ Coordenada caleatoria; Direccion daleatoria; for (int x=0;x<this->getNumPiezas();x++){ // this apunta a objetos de clase derivada colocaPieza(piezas[x],caleat); caleat.incrementa(daleat); } } private: Pieza piezas[MAX_PIEZAS]; }
Curso 07-08
63
Variable polimrfica utilizada como argumento de un mtodo: polimorfismo puro o mtodo polimrfico.
Proceso de deshacer el ppio. de sustitucin. Puede dar problemas. En C++: Child *c=dynamic_cast<Child *>(aParentptr); if (c!=0) { //nulo si no es legal, no nulo si OK }
Un solo mtodo puede ser utilizado con un nmero potencialmente ilimitado de tipos distintos de argumento.
Curso 07-08
64
}
Curso 07-08 65
Curso 07-08
66
{nombre=n;};
Curso 07-08
67
Curso 07-08
70
Ejemplo: Uso de polimorfismo y jerarqua de tipos int main(){ Empleado uno("Carlos", "lavanderia"); Estudiante dos("Juan", "empresariales"); Persona desc("desconocida"); desc=uno; //le asigno empleado cout << desc.getDatos() << endl; return (0); }
Curso 07-08
73
Ejemplo: Uso de polimorfismo y jerarqua de tipos int main(){ Empleado uno("Carlos", "lavanderia"); Estudiante dos("Juan", "empresariales"); Persona desc("desconocida"); desc=uno; //un empleado es una persona cout << desc.getDatos() << endl; }
Polimorfismo
Consecuencias para la definicin de destructores en jerarquas int main(){ Empleado *uno= new Empleado("Carlos", "lavanderia"); Estudiante *dos= new Estudiante("Juan", "empresariales"); Persona *desc; desc = uno; cout<<uno->getDatos()<<endl; cout<<dos->getDatos()<<endl; cout << desc->getDatos() << endl; delete desc; desc=NULL; delete dos; dos=NULL; uno=NULL; }
Liberar correctamente la memoria este main? Qu harais para subsanar el error sin cambiar el cdigo del main?
Curso 07-08 77
Polimorfismo
Cada clase con funciones virtuales dispone de un vector de punteros llamado v_table. Cada puntero corresponde a una funcin virtual, y apunta a su implementacin ms conveniente (la de la propia clase o, en caso de no existir, la del ancestro ms cercano que la tenga definida) Cada objeto de la clase tiene un puntero oculto a esa v_table.
Curso 07-08
78
Polimorfismo
Ventajas
El polimorfismo hace posible que un usuario pueda aadir nuevas clases a una jerarqua sin modificar o recompilar el cdigo original.
Estableces clase base Defines nuevas variables y funciones Ensamblas con el cdigo objeto que tenas Los mtodos de la clase base pueden ser reutilizados con variables y parmetros de la clase derivada.
Permite programar a nivel de clase base utilizando objetos de clases derivadas (posiblemente no definidas an): Tcnica base de las libreras/frameworks
Curso 07-08
79
Necesario (funciones virtuales puras) Posible (funciones virtuales donde existe refinamiento/reemplazo en las clases hijas)
Curso 07-08
80
Indice
1. Motivacin y conceptos previos
Signatura y mbito Tiempo de enlace Denicin Tipos de polimorsmo Sobrecarga basada en mbito Sobrecarga basada en signatura de tipo Alternativas a la sobrecarga Redenicin Shadowing Sobrescritura La variable receptora Downcasting Polimorsmo puro Funciones genricas en C++ Plantillas de clase en C++ Herencia en clases genricas
2.
Polimorsmo y reutilizacin
3.
Sobrecarga
4.
5.
Variables polimrcas
6.
Genericidad
Curso 07-08
81
Genericidad
Motivacin
La genericidad es otro tipo de polimorfismo Para ilustrar la idea de la genericidad se propone un ejemplo:
Suponed que queremos implementar una funcin mximo, donde los parmetros pueden ser de distinto tipo (int, double, float) Qu harais?
Curso 07-08
82
Genericidad
Motivacin
Solucin:
double maximo(double a, double b){ if (a > b) return a; else return b; }; int main (void){ int y,z; float b,c; double t,u; double s= maximo(t,u); double a= maximo((double)b,(double)c); double x= maximo((double)y,(double)z); }
Curso 07-08 83
Genericidad
Motivacin
Ahora suponed que creamos una clase TCuenta, y tambin queremos poder compararlas con la funcin maximo().
Curso 07-08
84
Genericidad
Motivacin
1 Sobrecargar el operador > para TCuenta 2 Sobrecargar la funcin mximo para TCuenta TCuenta maximo(TCuenta a, TCuenta b){ if (a>b) return a; else return b; } void main (void){ double s,t,u; TCuenta T1,T2,T3; s= maximo(t,u); T1= maximo(T2,T3); } Conclusin: Tenemos dos funciones mximo definidas, una para double y otra para TCuenta, pero el cdigo es el mismo. La nica diferencia son los parmetros de la funcin y el valor devuelto por sta.
Curso 07-08 85
Genericidad
Motivacin
Y si no sabemos a priori los tipos que otros van a crear para ser comparados?
Necesitaramos una funcin genrica que nos sirviera para cualquier tipo sin necesidad de tener la funcin duplicada.
Curso 07-08
86
Genericidad
DEFINICION
Propiedad que permite definir una clase o una funcin sin tener que especificar el tipo de todos o algunos de sus miembros o argumentos.
Su utilidad principal es la de agrupar variables cuyo tipo base no est predeterminado (p. ej., listas, colas, pilas etc. de objetos genricos). Es el usuario el que indica el tipo de la variable cuando crea un objeto de esa clase. En C++ esta caracterstica apareci a finales de los 80.
Curso 07-08
87
Genericidad en C++:
Templates
Plantillas de funciones: son tiles para implementar funciones que aceptan argumentos de tipo arbitrario. Plantillas de clase: su utilidad principal consiste en agrupar variables cuyo tipo no est predeterminado (clases contenedoras)
Curso 07-08
88
Genericidad
Qu tendra que hacer para, aplicando la funcin mximo, poder obtener la cuenta con ms saldo?
Curso 07-08 89
Genericidad
Curso 07-08
90
Genericidad
template <class T> T min(T a, T b){} template <class T> T min(int a, T b){} template <class T> T min(int a, int b){} // pero int main() {
//OK
Genericidad
Plantillas de funciones: son tiles para implementar funciones que aceptan argumentos de tipo arbitrario. Plantillas de clase: su utilidad principal consiste en agrupar variables cuyo tipo no est predeterminado
Curso 07-08
92
Genericidad
Curso 07-08
93
Genericidad
Curso 07-08
94
Genericidad
template <class T> vector<T>::vector(int size) { tam=size; v=new T[size]; }; template <class T> T& vector<T>::operator[](int i) { return(v[i]); };
Curso 07-08 95
Genericidad
Curso 07-08
96
Genericidad
Curso 07-08
97
Genericidad
Curso 07-08
98
Genericidad
Ejemplo: Pila de Objetos Genrica template <class T> Pila<T>::Pila(int nelem){ if (nelem<=limite){ nelementos=nelem; } else { nelementos=limite; } info=new T[nelementos]; cima=0; };
Genericidad
Genericidad
int main(){ Pila <TCuenta> pCuentas(6); TCuenta c1("Cristina",20000,5); TCuenta c2("Antonio",10000,3); pCuentas.apilar(c1); pCuentas.apilar(c2); pCuentas.imprimir();
Genericidad
Clase base genrica: template <class T> class Pila{ public: void poner(T a): private: T* buffer; int cabeza; };
Curso 07-08
102
Genericidad
Curso 07-08
103
Genericidad
Clase base genrica: template <class T> class Pila{ public: void poner(T a): private: T* buffer; int cabeza; };
Curso 07-08
104
Genericidad
Curso 07-08
105
Genericidad
Constantes en plantillas
Los argumentos de una plantilla no estn restringidos a ser clases definidas por el usuario, tambin pueden ser tipos de datos existentes. Los valores de estos argumentos se convierten en constantes en tiempo de compilacin para una instanciacin particular del template. Tambin se pueden usar valores por defecto para estos argumentos.
Curso 07-08
106
Genericidad
Curso 07-08
107
Polimorfismo Resumen
Con las funciones virtual y el polimorfismo es posible disear e implementar sistemas que sean ms fcilmente extensibles. Es posible escribir programas para que procesen objetos de tipos que tal vez no existan cuando el programa est bajo desarrollo. La programacin polimrfica con funciones virtual puede eliminar la necesidad de lgica de switch. El programador puede utilizar el mecanismo de funcin virtual para realizar automticamente la lgica equivalente, evitando de esta forma los tipos de errores asociados con la lgica de switch. El cdigo cliente que toma decisiones acerca de tipos de objetos y representaciones es seal de un pobre diseo de clases. Las clases derivadas pueden proporcionar su propia implementacin de una funcin virtual de clase base, en caso de ser necesario, pero si no lo hacen se utiliza la implementacin de la clase base. Si se invoca una funcin virtual haciendo referencia a un objeto especfico por nombre y utilizando el operador punto de seleccin de miembros, la referencia se resuelve en tiempo de compilacin (a esto se le llama enlace esttico), y la funcin virtual que se llama es aqulla definida para (o heredada por) la clase de ese objeto particular.
108
Curso 07-08
Polimorfismo Resumen
Hay muchas situaciones en las cuales es til definir clases para las cuales el programador nunca pretende instanciar ningn objeto. A tales clases se les llama clases abstractas. Debido a que slo se utilizan como clases base, normalmente las mencionaremos como clases base abstractas. No es posible instanciar en un programa ningn objeto de una clase abstracta. Las clases de las que se pueden instanciar objetos son llamadas clases concretas. Una clase se hace abstracta mediante la declaracin de que una o ms de sus funciones virtual sean puras. Una funcin virtual pura es aqulla que tiene un inicializador de = 0 en su declaracin. Si una clase se deriva de una clase que tiene funciones virtual puras sin proporcionar una definicin para esa funcin virtual pura en la clase derivada, dicha funcin sigue siendo pura en la clase derivada. Por consecuencia, la clase derivada tambin es una clase abstracta (y no puede tener ningn objeto). C++ permite el polimorfismo la habilidad de que objetos de diferentes clases relacionados por herencia respondan en forma diferente a la misma llamada de funcin miembro.
109
Curso 07-08
Polimorfismo Resumen
El polimorfismo se implementa por medio de funciones virtual. Cuando se hace una peticin, por medio de un apuntador o referencia a clase base, para que se utilice una funcin virtual, C++ elige la funcin sobrepuesta correcta en la clase derivada adecuada que est asociada con el objeto. Mediante el uso de funciones virtual y el polimorfismo una llamada de funcin miembro puede causar diferentes acciones, dependiendo del tipo del objeto que recibe la llamada. Aunque no podemos instanciar objetos de clases base abstractas, s podemos declarar apuntadores hacia clases base abstractas. Tales apuntadores pueden utilizarse para permitir manejos polimrficos de objetos de clases derivadas cuando tales objetos se instancian a partir de clases concretas. Regularmente se agregan nuevos tipos de clases a los sistemas. Las nuevas clases son amoldadas mediante el enlace dinmico (tambin llamado enlace tardo). No es necesario saber el tipo de un objeto en tiempo de compilacin para que se pueda compilar una llamada de funcin virtual. En tiempo de ejecucin la llamada de funcin virtual se hace coincidir con la funcin miembro del objeto que la recibe.
110
Curso 07-08
Polimorfismo Resumen
El enlace dinmico permite que los ISV distribuyan software sin revelar sus secretos propios. Las distribuciones de software pueden consistir solamente de archivos de encabezado y archivos objeto. No es necesario revelar nada del cdigo fuente. Los desarrolladores de software despus pueden utilizar la herencia para derivar nuevas clases a partir de las que proporcionan los ISV. El software que funciona con las clases que proporcionan los ISV continuar funcionando con las clases derivadas y utilizar (por medio de enlace dinmico) las funciones virtual sobrepuestas que se proporcionan en esas clases. El enlace dinmico requiere que en tiempo de ejecucin la llamada a una funcin miembro virtual sea dirigida hacia la versin de la funcin virtual adecuada para esa clase. Una tabla de funciones virtuales, llamada vtable, est implementada como un arreglo que contiene apuntadores de funcin. Cada clase que contiene funciones virtual tiene una vtable. Para cada funcin virtual de la clase, la vtable tiene una entrada que contiene un apuntador a funcin hacia la versin de la funcin virtual que hay que utilizar para un objeto de esa clase. La funcin virtual que hay que utilizar para una clase particular podra ser la funcin definida en esa clase, o una funcin heredada directa o indirectamente de una clase base que est en un nivel ms elevado en la jerarqua.
Curso 07-08
111
Polimorfismo Resumen
Cuando una clase base proporciona una funcin miembro virtual, las clases derivadas pueden sobreponer a la funcin virtual pero no estn obligadas a hacerlo. Por lo tanto, una clase derivada puede utilizar la versin de la clase base de la funcin miembro virtual, y esto estara indicado en la vtable. Cada objeto de una clase que tiene funciones virtual contiene un apuntador hacia la vtable de esa clase. El apuntador a funcin adecuado en la vtable se obtiene y desreferencia para completar la llamada en tiempo de ejecucin. Esta bsqueda en la vtable y la desreferenciacin del apuntador requieren una sobrecarga nfima del tiempo de ejecucin, que por lo general es menor que el mejor cdigo cliente posible. Declare como virtual al destructor de la clase base si la clase contiene funciones virtual. Esto hace que todos los destructores de las clases derivadas sean virtual aunque no tengan el mismo nombre que el destructor de la clase base. Si un objeto de la jerarqua es destruido explcitamente por medio de la aplicacin del operador delete al apuntador de clase base a un objeto de clase derivada, se invoca el destructor de la clase adecuada. Cualquier clase que tenga uno o ms apuntadores 0 en su vtable es una clase abstracta. Las clases que no tengan un apuntador a vtable que sea 0 (como Point, Circle y Cylinder) son clases concretas.
Curso 07-08
112
Captulo 4
T. Budd.
Scott Meyers
Curso 07-08
113