Buenos días,
En otra ocasión se ha hablado sobre el tema de la herencia (http://delphiaccess....cepto-herencia/).
De la mano de éste concepto viene el polimorfismo. En esta oportunidad voy a ser más específico en esta potente capacidad.
Concepto
El polimorfismo es, en forma técnica, la capacidad que tiene un objeto de responder de múltiples formas a un mensaje en función de los parámetros que le son suministrados.
En forma sencilla, podemos decir que el polimorfismo es la capacidad que tienen los objetos de una clase de hacer diferentes cosas con un mismo método.
Caso Práctico
Si recuerdan del artículo anterior, habrán notado que se redefinió el método MuestraDatos en TPerro para añadir algo nuevo al MuestraDatos de TMamifero. Eso es polimorfismo, puesto que dependiendo del tipo (clase), se hace una u otra cosa. Como ven, el nombre no ha cambiado nada, sigue siendo el mismo.
Cuando mencioné el concepto he dicho "en función de los parámetros que le son suministrados". No vemos ningún parámetro en MostrarDatos ¿no?. En realidad hay uno pero se dá implícitamente: self. este parámetro se envía con el método sin intervención del programador. El compilador solito hace el trabajo.
¿Porqué existe ese parámetro? Existe por una razón: identificar la clase y al objeto que lo invoca. Sin éste, el compilador no sabría a quien le pertenece el método. En el caso de MostrarDatos, se usa a "Self" para verificar si debe aplicar MostrarDatos de la clase base o de una hija.
Repetiré el ejemplo para ser más gráfico:
type TMamifero = class(TObject) ... procedure MostrarDatos; virtual; end; TPerro =class(TMamifero) ... procedure MostrarDatos; override; end;
Para trabajar con ambos hacemos algo como esto:
var Mamifero: TMamifero; Perro: TPerro; begin Mamifero := TMamifero.Create; ... Mamifero.MostrarDatos; Perro := TPerro.Create; ... Perro.MostrarDatos; end;
¿Me creerían que podemos trabajar con ambas clases, sin depender de si es TPerro, o TMamifero, TGato o cualquier descendiente que se plantee a TMamifero?.
Si, si se puede. Y eso es otra de las ventajas que nos ofrece el polimorfismo: trabajar con muchas clases, independiente del tipo (clase). Operaremos de forma común a todas ellas, y por tanto es necesario que existe una clase base común a todas.
Esto nos permite hacer cosas como esto:
var Mamifero: TMamifero; begin Mamifero := TMamifero.Create; ... Mamifero.MostrarDatos; // ejecutará el MostrarDatos de TMamifero Mamifero := TPerro.Create; // Si, ¡está bien! Es polimorfirmo ... Mamifero.MostrarDatos; // ejecutará el MostrarDatos de TPerro end;
Como ven, tenemos una variable de clase TMamifero y con esta misma variable podemos "jugar" con distintos animales que desciendan de TMamifero. Esto es posible gracias a aquel "self" que he comentado antes.
Pero no es posible hacer algo como esto:
var Perro: TPerro; begin Perro := TMamifero.Create; // ¡El compilador nos da error! end;
¿Porqué la inversa no es posible? Porque podemos inferir que todo perro es un mamífero, pero no que todo mamífero es un perro. Técnicamente el compilador determina si en la tabla de memoria, es posible dicha asignación.
El polimorfismo funciona siempre y cuando los descendientes tengan algo en "común".
Espero que este mini ejemplo ilustre de forma más completa el concepto de polimorfismo.
Saludos,