5. Il polimorfismo
Tra i vari tipi di polimorfismo [Cardelli85] che possono essere presenti in un linguaggio, quello che si deve necessariamente ritrovare nella programmazione ad oggetti noto come polimorfismo di inclusione universale, basato proprio sul concetto di ereditarietà. Questa forma di polimorfismo si basa sui seguenti presupposti:
a) la possibilità di usare variabili polimorfe, cioè che possono riferirsi ad oggetti di tipi diversi (generalmente "inclusi" in una certa . In pratica basta permettere ad una variabile di tipo T di ricevere un oggetto di un qualsiasi sottotipo di T.
b) la possibilità di effettuare chiamate polimorfe, cioè di indicare con lo stesso nome dei metodi che appartengono a classi diverse e che sono quindi generalmente diversi ("polimorfo" = "avente pi forme").
A differenza di altre forme di polimorfismo, come l'overloading (sovraccarico o sovrapposizione) degli operatori, il polimorfismo di inclusione universale prevede che la decisione su quale debba essere la routine da richiamare viene presa a tempo di esecuzione a seconda della classe effettiva (pi stretta) di appartenenza dell'oggetto rispetto a cui viene fatta la chiamata. Questa tecnica nota come collegamento dinamico (late o dynamic binding) dei nomi al codice che deve essere effettivamente eseguito. Esso si contrappone al tradizionale collegamento statico (early o static binding) deciso dal compilatore, di norma, nel caso di chiamate non polimorfe.
Spesso il polimorfismo viene introdotto con le classe astratte, vale a dire classi in cui compaiono uno o pi metodi la cui definizione viene rinviata alle sottoclassi (metodi astratti). Tipico l'esempio rappresentato nella figura qui sotto, in cui la classe
ANIMALE ha un metodo astratto fai_verso() che trova una concreta realizzazione (definizione) solo nei discendenti "concreti" (ad es. CANE, GATTO, ecc. ).
|
Il polimorfismo trova applicazione soprattutto in schemi simili a quello esemplificato dal seguente frammento:
per
ogni a : ANIMALE in S eseguiSi immagina che la variabile
a assuma di volta in volta i vari oggetti (di tipo ANIMALE) che si trovano in un insieme o in un array S. Alla variabile a verr quindi di volta in volta associato un animale potenzialmente diverso e a priori sconosciuto. Quindi, per il compilatore, la chiamata a.fai_verso() polimorfa e, come tale, soggetta al collegamento dinamico.