Se hai chiari i concetti di base della programmazione Object Oriented le cose risultano piuttosto facili. Partiamo da un concetto che userò come esempio:
Ho una classe (astratta) Figura.
Da tale classe posso derivare diverse sottoclassi: Triangolo, Rettangolo, Cerchio.
Dalla classe Rettangolo posso derivare un'ulteriore classe: Quadrato.
Prendiamo ora la classe Triangolo. Essendo derivata da Figura, la classe Triangolo è una Figura. Messa in questi termini dovrebbe risultare facile.
Questo è il concetto fondamentale chiamato Ereditarietà. Una classe B che deriva da una classe A è, per ereditarietà, anche di tipo A.
Che cos'è, quindi, un Up-Cast? Nel nostro esempio, è quell'operazione che "forza" un oggetto di tipo Triangolo ad essere visto come di tipo "Figura". Siccome la classe Triangolo deriva dalla classe Figura è facile capire che l'Up-Cast è "abbastanza inutile". Diventa necessario solo in particolari casi (vedremo dopo).
Esempio:
codice:
Triangolo t = new Triangolo( ... );
elaboraOggetto( (Figura) t ); // Up-Cast
// Ma potevo tranquillamente scrivere anche così:
elaboraOggetto( t ); // l'up-cast è sempre automatico (quando non ambiguo)
Un Down-Cast è l'esatto opposto: se hai un oggetto di tipo Figura (perchè sei all'interno di un metodo che accetta oggetti di tale tipo) non sai a priori di quale figura si tratti (potrebbe essere un Triangolo, un Rettangolo, un Quadrato o un Cerchio). Si possono effettuare dei test per verificare esattamente di quale classe sia l'oggetto. Una volta capito di che tipo è, potresti aver bisogno di usarne i metodi specifici... per questo ti serve un Down-Cast.
Esempio:
codice:
public void elaboraFigura(Figura f) {
// Ok... che figura ho?
if (f instanceof Cerchio) {
// E' un cerchio... ottengo il centro
Cerchio c = (Cerchio) f; // Down-Cast
Point centro = c.getCentro();
}
...
}
Torniamo all'Up-Cast... che succede se ho un metodo sottoposto ad override? Supponiamo che la classe Triangolo implementi una interfaccia (esempio, "Ruotabile"). Bene... se ho un metodo che si chiama "ruota()" che prende un oggetto Figura e un altro metodo "ruota()" che prende un oggetto Ruotabile... come faccio a decidere quale dei due voglio usare? Qui sono obbligato ad effettuare un Up-Cast per specificare esattamente quale implementazione usare:
codice:
public void ruota(Figura f) { ... }
public void ruota(Ruotabile r) { ... }
...
Triangolo t = new Triangolo( ... );
ruota( (Figura) t ); // Up-Cast per usare il metodo ruota(Figura f)
ruota( (Ruotabile) t ); // Up-Cast per usare il metodo ruota(Ruotabile r)
Ciao.