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 esegui
    a.fai_verso()
fine per ogni

Si 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.