Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
Genricamente, el polimorfismo es la capacidad de tomar varias formas. Aplicado a los lenguajes de programacin, debemos considerar dos tipos de polimorfismo: polimorfismo funcional y polimorfismo de datos.
I-3-1
Polimorfismo funcional en lenguajes orientados a objetos. En los LOO, las operaciones se aplican siempre a un objeto. El mtodo que se ejecuta viene determinado por la clase a la que pertenece el objeto que recibe el mensaje. Por este motivo no hay limitaciones a la sobrecarga de funciones definidas en clases distintas. En Smalltalk, dado que no se realiza comprobacin de tipos, sta es la nica posibilidad de sobrecarga, puesto que no es posible distinguir dos mtodos en base a las clases de los argumentos. As: p distancia: q hace referencia a mtodos distintos dependiendo de si p es un Punto o un Segmento, pero el mtodo que se ejecuta no depende de la clase a la que pertenece q. En Java, s se permite la sobrecarga dentro de una clase. Al igual que ocurre en ADA, el mtodo invocado viene determinado por los tipos o clases de los argumentos, pero no por el tipo del resultado. Ej. Los constructores de una clase Sin embargo, dado que Java hace en ocasiones conversiones de tipos implcitas, ciertas sobrecargas no estn permitidas: class Sobrecargada { int valor; void setValor ( int v ) { valor = v; } void setValor (float v) { valor = v; } // Error int getValor ( ) { return valor; } float getValor ( ) { return ( float ) valor; } // Error }
I-3-2
I-3-3
Lenguajes procedimentales En lenguajes procedimentales con comprobacin estricta de tipos, como ADA, no existe polimorfismo, puesto que los tipos son incompatibles, y las conversiones deben ser explcitas: p : REAL; p := REAL(3);
Otros lenguajes con comprobaciones de tipos menos estrictas, como C, realizan algunas conversiones de forma automtica: float p = 3; // Equivale a float p = (float) 3; pero esto no es polimorfismo, puesto que el dato se convierte al tipo esttico de la variable que lo referencia. Lenguajes orientados a objetos En un lenguaje orientado a objetos y sin comprobacin de tipos, como Smalltalk, el polimorfismo es total. Cualquier identificador puede hacer referencia a cualquier objeto, pero esta flexibilidad absoluta tiene como contrapunto una mayor dificultad en la deteccin y correccin de errores. |p| p := 3. p := Punto new.
En un lenguaje orientado a objetos y con comprobacin de tipos, como Java, el polimorfismo est limitado por la herencia. Un identificador puede hacer referencia a cualquier objeto cuyo tipo sea descendiente del tipo esttico del identificador. Esto asegura que la correccin del cdigo pueda determinarse en tiempo de compilacin. Punto p, q; p := new Particula(1.0, 2.0, 3.0); p.trasladar(1.0,2.0); p.atraccin(q) // Error de compilacin
I-3-4
I-3-5
I-3-6
La implementacin de los operadores relacionales es la siguiente: los mtodos >, y estn definidos en la clase Magnitude haciendo referencia al mtodo <, mientras que este ltimo invoca al mtodo implementedBySubclass de la clase Object, cuyo objetivo es proporcionar un mensaje advirtiendo que debera existir una redefinicin del mtodo en las subclases. Cada subclase de Magnitude implementa el mtodo < de acuerdo a la representacin interna especfica de magnitud de que se trate. < unaMagnitud ^self implementedBySubclass > unaMagnitud ^ unaMagnitud < self <= unaMagnitud ^ (self > unaMagnitud) not >= unaMagnitud ^(self < unaMagnitud) not
En cualquier caso no se trata de una clase abstracta en sentido estricto puesto que el interprete de Smalltalk no tiene forma de comprobarlo y no puede impedir la creacin de instancias. Los posibles errores se producirn en tiempo de ejecucin. Java (ver apuntes de introduccin a Java)
I-3-7
I-3-8
Herencia repetida. Un problema asociado a la herencia mltiple es la herencia repetida. Pueden surgir situaciones en las que se herede de una misma clase por caminos distintos, de forma que las mismas caractersticas se heredan a travs de dos o mas clases padres, pudiendo producirse entonces un conflicto. Ninguna estrategia de bsqueda (en profundidad, en amplitud) puede resolver estos conflictos de forma adecuada en todas las situaciones:
Animal marino
respirar_en = agua tipo = salvaje
Animal de acuario
tipo = domstico
Cetceo
respirar_en = aire
Delfn
Delfn de acuario
La bsqueda en profundidad falla para la caracterstica respirar_en (si empieza por la izquierda) o para tipo (si es por la derecha). La bsqueda en amplitud, falla para respirar_en, que tiene definiciones contrarias a distancia dos.
I-3-9
C++
A valor
D getValor( )
C++ evita la ambigedad en la herencia repetida obligando a utilizar el operador de mbito cuando, desde la clase hija, se haga referencia a una caracterstica repetida: public: int getValor( ) { return B::valor; } // o bien C::valor
Esta solucin resuelve los conflictos, pero los atributos estn repetidos en la clase hija. Para indicar que deseamos slo una copia, debemos utilizar herencia virtual: class B : public virtual A { . . . }; class C : public virtual A { . . . }; class D : public B, public C { public: int Valor( ) { return valor; }; }
La situacin se complica si queremos que determinados atributos se hereden varias veces, mientras que otros se hereden slo una vez y,. En el caso de los mtodos, los conflictos surgen cuando alguno de los padres redefine dichos mtodos.
I - 3 - 10
5. Clases genricas.
Otro mecanismo para aumentar la flexibilidad y reutilizacin del cdigo es la posibilidad de definir mdulos genricos. Esta posibilidad es especialmente interesante a la hora de implementar estructuras de datos complejas, que contienen elementos de otros tipos, tales como listas, matrices, rboles, etc. La herencia y la genericidad son complementarias, podemos simular una mediante la otra. Sin embargo, en ocasiones la solucin de un problema es ms sencilla mediante herencia y en otras mediante genericidad. ADA es el mejor ejemplo de un lenguaje con mdulos genricos: permite la definicin de paquetes y funciones con parmetros formales, que pueden ser instanciados tanto con tipos como con datos. Existe adems la posibilidad de exigir que los parmetros reales que instancien los formales cumplan determinadas condiciones. generic type T is private with function + (a, b : T ) return T is <>; package LISTA is ... Tanto Java como Smalltalk resuelven la cuestin de la genericidad mediante polimorfismo, irrestringido en Smalltalk o sometido a la herencia en Java (ver apuntes de introduccin a Java). C++ permite definir clase genricas mediante templates. El cdigo de la clase genrica es expandido por el precompilador cuando se instancia la clase. Las clases genricas de C++ pueden tener como argumentos tanto clases como variables.
I - 3 - 11
C++ template < class T, int i > class Pila { T pila[i]; int n_elem; public: Pila( ); int vacia( ), llena( ); int insertar(T item); int extraer( ); T* cima( ); }; template < class T, int i > Pila< T, i >::Pila( ) { n_elem = 0; } template < class T, int i > int Pila< T, i >::vacia( ) { return ( n_elem == 0 ); } template < class T, int i > int Pila< T, i >::llena( ) { return ( n_elem == i ); } template < class T, int i > int Pila< T, i >::insertar(T item) if ( ! llena( ) ) } template < class T, int i > int Pila< T, i >::extraer( ) if ( ! vacia( ) ) } template < class T, int i > T* Pila< T, i >::cima( ) { if ( ! vacia( ) ) } return &pila[n_elem-1]; else return NULL; { n_elem--; return 0; } else return 1; { { pila[n_elem] = item; else return 1; { n_elem++; return 0; }
I - 3 - 12
#include <iostream.h> #include Pila.hpp void main() { Punto x1(1.0,2.0), x2(1.1,2.1); Pila<int,10> p1; Pila<Punto,5> p2; p1.insertar(1); p1.insertar(2); cout << *(p1.cima()); p1.extraer(); cout << *(p1.cima()); p1.extraer(); p2.insertar(x1); p2.insertar(x2); cout << *(p2.cima()); p2.extraer(); cout << *(p2.cima()); }
I - 3 - 13
Dificultades:
= Implementar un mdulo de bsqueda de propsito general, con independencia del tipo de los elementos contenidos, y de las caractersticas especficas de la estructura (array, lista, rbol...) = Especificar el mdulo de tal forma que los clientes puedan utilizarlo sin conocer nada acerca de su implementacin.
I - 3 - 14
Polimorfismo de datos.
Permite que una referencia para que denote objetos de clases distintas. Estructura *estructura; estructura = new ArbolBinario( ); Permite escribir mdulos independientes de los tipos de datos de los objetos con los que van a ser utilizados.
Vinculacin dinmica.
Da sentido al polimorfismo, al permitir que una misma llamada se interprete de manera distinta, eligindose la implementacin adecuada en tiempo de ejecucin, dependiendo del tipo del objeto receptor: estructura->buscar(x); Par ello es necesario un lenguaje con comprobacin de tipos estricta, donde el compilador tiene suficiente informacin sobre los tipos como para elegir la versin apropiada de una funcin.
I - 3 - 15
Generalidad La generalidad es la capacidad para definir mdulos parametrizados. Un mdulo parametrizado, llamado mdulo genrico, no se usa directamente, sino que funciona como mdulo patrn. En el caso ms usual, los parmetros (llamados parmetros genricos formales) se utilizan para representar tipos. Los mdulos reales, llamados particularizaciones o instancias de los mdulos genricos, se obtienen facilitando tipos reales (parmetros genricos reales) para cada uno de los parmetros genricos formales.
Un mdulo genrico tpico es: ArbolBinario[T] donde el parmetro genrico formal T, representa el tipo de los elementos del rbol binario. As, en vez de varios mdulos muy parecidos, uno para cada tipo de elementos, podemos tener un nico mdulo genrico ARBOL_BINARIO [T], que puede ser utilizado con distintos valores en el parmetro: ArbolBinario [INTEGER] ArbolBinario [REAL]
class ArbolBinario[T] nodo : T; iza, der : ArbolBinatio[T]; buscar (x:T) return boolean is begin Implementacin de 'buscar' end end;
I - 3 - 16
Polimorfismo y Generalidad. Repaso. El polimorfismo y la generalidad permiten posibilidades simtricas: = El polimorfismo facilita la programacin de los mdulos clientes. Hace posible escribir el mismo cdigo en el mdulo cliente para usar diferentes implementaciones de una estructura de datos. = La generalidad es relativa a la programacin de los mdulos en s mismos. Permite escribir el mismo cdigo para describir todas las particularizaciones de la misma implementacin de una estructura de datos, aplicada a varios tipos de objetos.
I - 3 - 17