Oggetti in C# Lezione 5 Polimorfismo I Andrea Zoccheddu
Facciamo chiarezza Abbiamo visto che è possibile ridefinire i metodi di una classe derivata Ma in realtà esistono due differenti modi di re-dichiarazione: 1. OVERLOADING, sovrapposizione 2. OVERRIDING, scavalcamento
OVERLOADING È il modo più semplice di ridefinire un metodo La classe discendente semplicemente lo dichiara e definisce di nuovo class Felino { public void Verso() Console.WriteLine("MEOW"); } }//Felino class Gatto : Felino { public void Verso() Console.WriteLine("MIAO"); } }//Gatto
OVERLOADING È il modo più semplice di ridefinire un metodo Il metodo è legato staticamente Il f1 chiama il verso del Felino Il g1 chiama il verso del Gatto Felino f1 = new Felino(); f1.Verso(); Gatto g1 = new Gatto(); g1.Verso(); MEOW MIAO
OVERLOADING Nella ridefinizione si può invocare il metodo del padre Il metodo può sfruttare quanto predisposto dal metodo paterno class Felino { public void Verso() Console.WriteLine("MEOW"); } }//Felino class Gatto : Felino { public void Verso() base.Verso(); Console.WriteLine("MIAO"); } }//Gatto
OVERLOADING È il modo più semplice di ridefinire un metodo Il metodo è legato staticamente Il f1 chiama il verso del Felino Il g1 chiama il verso del Gatto Felino f1 = new Felino(); f1.Verso(); Gatto g1 = new Gatto(); g1.Verso(); MEOW MEOW MIAO
un caso particolare Andrea Zoccheddu
i metodi Contento sono molto simili Un caso particolare Ma si osservi questa situazione: class Felino { public void Fusa () Console.WriteLine("Grrr"); } public void Contento() this.Fusa(); Console.WriteLine("Struscia"); }//Felino class Gatto : Felino { public void Fusa () Console.WriteLine("Prrr"); } public void Contento() this.Fusa(); Console.WriteLine("Struscia"); }//Gatto i metodi Contento sono molto simili
Un caso particolare Quando si invocano i metodi essi si comportano bene: Però quei metodi «Contento» sono proprio identici… è possibile evitare di ripetere il secondo? In fondo il metodo è ereditato dal padre ... Felino f1 = new Felino(); f1.Contento(); Gatto g1 = new Gatto(); g1. Contento(); GRRR Struscia PRRR Struscia
il metodo Contento è ereditato da Gatto Un caso particolare Le definizioni diventerebbero: class Felino { public void Fusa () Console.WriteLine("Grrr"); } public void Contento() this.Fusa(); Console.WriteLine("Struscia"); }//Felino class Gatto : Felino { public void Fusa () Console.WriteLine("Prrr"); } }//Gatto il metodo Contento è ereditato da Gatto
Un caso particolare Quando si invocano i metodi però: Il metodo Contento del gatto usa il metodo Fusa del Felino invece del suo, ed il motivo è il legame statico Felino f1 = new Felino(); f1.Contento(); Gatto g1 = new Gatto(); g1. Contento(); GRRR Struscia GRRR Struscia
Un caso particolare Il problema lo causa il metodo Contento del Felino Quando viene compilato il riferimento al metodo Fusa è statico e quindi impone un collegamento fisso Anche se è un Gatto che invoca il metodo Contento ormai il metodo è legato al metodo Fusa del Felino
Un caso particolare Invece vorremmo che il collegamento fosse «al volo» ovvero dinamico, a tempo di esecuzione del programma Così magari la macchina si accorge che si tratta di un Gatto e non di un Felino generico
polimorfismo OVERRIDING I METODI VIRTUALI Andrea Zoccheddu
il metodo Contento è ereditato OVERRIDING La situazione si può risolvere così class Felino { public virtual void Fusa () Console.WriteLine("Grrr"); } public void Contento() Fusa(); Console.WriteLine("Struscia"); }//Felino class Gatto : Felino { public override void Fusa () Console.WriteLine("Prrr"); } }//Gatto il metodo Contento è ereditato
Un caso particolare Quando si invocano i metodi essi si comportano bene: Cosa accade? Il collegamento al metodo Fusa è ritardato: si aspetta l’esecuzione della invocazione per decidere quale metodo invocare Felino f1 = new Felino(); f1.Contento(); Gatto g1 = new Gatto(); g1. Contento(); GRRR Struscia PRRR Struscia
polimorfismo Il polimorfismo è il concetto che una istanza può invocare un nome di metodo che si aggancia dinamicamente al metodo corretto «al volo» Il polimorfismo è un paradigma di programmazione, ovvero un modello ed una tecnica di realizzazione dei programmi Rappresenta un modello elevato di efficienza e flessibilità
virtual virtual è una parola riservata Un metodo virtual è dichiarato come un metodo con collegamento ritardato Il metodo verrà cercato a partire dal tipo di istanza legata alla variabile effettiva che la invoca Il metodo può essere ridefinito con override
virtual L’ordine in cui compaiono le parole public e virtual non è importante. Una funzione virtuale non può essere privata, o si ha un errore di compilazione. Infatti una funzione privata non può essere visibile e accessibile dalle classe derivate
override override è una parola riservata Un metodo override indica come eseguire il metodo nel caso di una istanza specifica Un metodo virtuale deve essere ridefinito con override per ottenere un collegamento dinamico Se uso di nuovo virtual invece sto scavalcando il metodo
override Una funzione con override deve fare riferimento ad una antenata virtuale o si ha un errore Il prototipo della funzione ridefinita deve coincidere perfettamente con quello della funzione base (public, tipo, parametri) o si ha un errore