Você está na página 1de 17

3. Polimorfismo.

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.

3.1. Polimorfismo funcional o sobrecarga.


El polimorfismo funcional es la posibilidad de referenciar, mediante el mismo identificador, diferentes funciones. La mayora de los lenguajes de programacin presentan sobrecarga de operadores. En algunos, tambin las funciones de entrada/salida estn sobrecargadas, pero slo unos pocos admiten el polimorfismo en funciones definidas por el programador. Para que exista sobrecarga, el lenguaje debe realizar comprobacin de tipos. Este es el caso de ADA, donde el compilador determina la funcin que va a ser invocada dependiendo del tipo de los argumentos: buscar(a: Array, e: elemento) : Integer; buscar(l : Lista, e: elemento) : Integer; Sin embargo, en lenguajes sin comprobacin de tipos estricta, como C, no se permite la sobrecarga, pues puede producirse ambigedad: int a; funcin ( a ); podra interpretarse como una llamada a una de estas dos funciones void funcin ( int x ); void funcin ( float x );

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

3.2. Polimorfismo de datos.


El polimorfismo de datos es la capacidad de un identificador para hacer referencia a instancias de distintas clases. El polimorfismo de datos es una caracterstica de los lenguajes orientados a objetos. El polimorfismo de datos aumenta las posibilidades de reutilizacin de cdigo, favoreciendo la construccin de mdulos como extensin de otros ya existentes. En los lenguajes con polimorfismo de datos es necesario distinguir entre: = tipo esttico: tipo con el que se declara una referencia o variable. = tipo dinmico: tipo de objeto asociado a una referencia en un momento dado. En muchos lenguajes, el polimorfismo de datos sta limitado por las relaciones de herencia: el tipo dinmico ha de ser un descendiente del tipo esttico. Las razones son dos: = cualquier intancia de una clase es instancia de las clases antecesoras. p : Punto; r : Particula; p := r; = cualquier instancia de una clase posee los atributos declarados por las clases antecesoras y entiende los mtodos definidos por ellas. x := p.abscisa; p.distancia(r);

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

3.3. Vinculacin dinmica.


La vinculacin dinmica es el complemento esencial del polimorfismo. Cuando existe polimorfismo una entidad puede hacer referencia a objetos de clases distintas, y un mtodo puede tener diversas implementaciones. Al enviar un mensaje a un objeto: referencia.mtodo(argumentos); el mecanismo de vinculacin dinmica asegura que el mtodo que se ejecuta es el definido para el tipo dinmico. La vinculacin dinmica supone una mayor carga para el sistema en tiempo de ejecucin, pero abre nuevas posibilidades durante la programacin al hacer efectivamente posible la reutilizacin de cdigo. Tanto Smalltalk como Java resuelven todas las llamadas mediante vinculacin dinmica (excepto los mtodos declarados como final en Java).

I-3-5

3.4. Clases abstractas.


Existen clases que aunque especifican su interfaz no pueden implementar completamente los mtodos correspondientes, debido a que sus subclases pueden tener diferentes representaciones. (atributos). Estas clases reciben el nombre de clases abstractas. Las clases abstractas sern superclases de otras concretas, que implementan la interfaz. El objetivo de una clase abstracta es el de especificar el interfaz comn a todas sus subclases. Estas sern las que se encarguen de implementar los aspectos especficos de dicho interfaz. Como una clase abstracta no implementa del todo su interfaz, no tiene sentido crear instancias suyas, puesto que a estas instancias no se les podrn aplicar los mtodos no implementados. Smalltalk La forma de definir clases abstractas en Smalltalk es indicando que los mtodos correspondientes han de ser implementados por las subclases: Por ejemplo: la clase Magnitude es una clase abstracta usada en Smalltalk para describir objetos que pueden ser comparados. Las subclases suyas son: Character, Date, Number y Time. El protocolo comn especificado por la clase Magnitude refleja el hecho de que toda instancia de cualquier subclase puede ser comparada con otra usando los operadores relacionales usuales. De este modo, podremos preguntar si un nmero es menor que otro, o si una fecha es mayor que otra.

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

4. Herencia mltiple y repetida.


Algunos LOO, como Smalltalk, disponen nicamente de herencia simple: una clase slo puede heredar de otra, y el diagrama de herencia tiene forma de rbol. Sin embargo, C++ tiene herencia mltiple: existe la posibilidad de heredar no slo de una clase sino de varias, de forma que se pueden combinar comportamientos y el diagrama de herencia tiene forma de grafo acclico. La subclase hereda las caractersticas de cada una de sus superclases. C++ class Circulo { public: double radio; Circulo ( double r ) { radio = r; } double area ( ) { return radio * radio * 3.14; } }; class Mesa { public: double altura; Mesa ( double h ) { altura = h; } }; class MesaRedonda : public Mesa, public Circulo { public: int color; MesaRedonda ( double h, double r, int c ) : Circulo ( r ), Mesa ( h ) { color = c; } };

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

6. Reutilizacin de cdigo en los lenguajes orientados a objetos.


Deberan existir catlogos de mdulos de software, de forma que la construccin de un nuevo sistema no consistiese ms que en pedir determinadas componentes de ese catlogo, y combinarlas adecuadamente; en vez de reinventar cosas una y otra vez. Consideremos el problema de bsqueda general: Dado un elemento x de cierto tipo, y un conjunto t de elementos del mismo tipo, determinar si el elemento x aparece o no en t. La forma general del cdigo es la misma en cualquier caso:
buscar (x:ELEMENTO) return boolean is pos:POSICION begin pos := POSICIN_INICIAL( ); while not FIN(pos) and then not ELEMENTO(pos) = x do pos := SIGUIENTE(pos) end; return not FIN(pos) end --buscar

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

Cmo podemos tener en cuenta esta variabilidad?


El polimorfismo (de datos y funcional) y la generalidad son dos soluciones para este problema.

Polimorfismo funcional (sobrecarga de operaciones).


Gracias a la sobrecarga, una llamada a cualquiera de las funciones sobrecargadas tendr siempre la misma forma. buscar(x) Por s sola, la sobrecarga no es ms que una utilidad sintctica.

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.

Cmo favorecen la reutilizacin?


= La generalidad es una solucin al problema de variacin de tipos. = El polimorfismo aparece como una forma de tener en cuenta la variacin de las estructuras de datos y algoritmos; adems permite utilizar una operacin sin conocer su implementacin y sin saber cul es la implementacin que se va a utilizar. Para alcanzar este grado de flexibilidad, esencial para la construccin de software reutilizable, debemos recurrir al diseo orientado a objetos.

I - 3 - 17

Você também pode gostar