Una delle caratteristiche più interessanti della programmazione a oggetti è la possibilità di creare degli oggetti che si basano su oggetti creati precedentemente, per formarne altri più complessi. Questa caratteristica è chiamata "inheritance" (eredità) ed è uno strumento molto potente per il programmatore, ma anche, sotto molti aspetti, complesso da utilizzare al meglio.
Disegnando un oggetto che si intende poi rendere ereditabile in modo efficace è necessaria una lunga sessione di pianificazione dell’oggetto stesso: cosa si desidera rendere pubblico e cosa invece mantenere nascosto, tenendo presente che un oggetto "figlio" vedrà solo le parti pubbliche dell'oggetto originario.
CLASSE: è un oggetto completo di variabili interne e di procedure di manipolazione.
ROOTCLASS: è la classe di base sulla quale si appoggiano altri oggetti.
SUPERCLASS: è la classe precedente a quella attuale, diciamo il "padre" dell'oggetto corrente.
METODO: è una funzione di un oggetto.
COSTRUTTORE: è il metodo utilizzato per inizializzare un oggetto.
DISTRUTTORE: è il metodo utilizzato per eliminare un oggetto, liberando tutte le risorse allocate da questo.
OBJECT nome_oggetto OF oggetto_padre definizione... definizione... ENDOBJECT
Per il resto si procede esattamente come nella creazione di un singolo oggetto.
Supponiamo di avere un oggetto "immagine" così definito:
OBJECT immagine PRIVATE cols:PTR TO cmap bmp :PTR TO bitmap ENDOBEJCT
e che siano definiti questi metodi:
bitmaptoscreen(scr:PTR TO screen) - Usato per visualizzare la bitmap su di uno schermo. colorstoscreen(scr:PTR TO screen) - Usato per settare la palette a quella dell'immagine.
Con questi metodi è possibile, effettivamente mostrare una immagine, e l'utilizzatore dell'oggetto non dovrà mai preoccuparsi di sapere dove effettivamente risiedono i puntatori alla bitmap ed alla colormap: questo è molto sicuro dal momento che le risorse allocate dall'oggetto saranno liberate dall'oggetto stesso: quindi non dovrebbero esserci problemi. Ma supponiamo che si desideri creare un oggetto chiamato "remapper" che si occupi di permettere il remap di un oggetto "immagine" con una palette differente da quella dell'oggetto stesso.
L'oggetto "remapper" deve essere in grado di accedere (e modificare) ai dati dell'oggetto "immagine": quindi dovremo definire questi due metodi (ancora nell'oggetto "immagine"):
bitmap() - Restituisce il puntatore alla bitmap cols() - Restituisce il puntatore alla colormap
E dovranno essere creati anche metodi che permettano la creazione e la distruzione di "parti" dell'oggetto:
alloc(width, height, depth) - Alloca una bitmap free() - Libera la bitmap
L'oggetto "remapper" dovrà così essere costruito:
OBJECT remapper OF immagine ENDOBJECT remap(pal:PTR TO cmap) IS self.makeremap(SUPER self.bitmap(), SUPER self.cols(), pal)
Il metodo remap() che ho appena descritto ha delle peculiarità interessanti delle quali è meglio parlare subito. Innanzitutto, notate la parola chiave SUPER che permette di chiamare un metodo di un oggetto precedente al corrente. Questo è necessario, ad esempio nel nostro caso, poichè l'oggetto "remapper", ereditando completamente "immagine" ne possiede anche i metodi "bitmap()" e "cols()", che però, nell'oggetto in questione, sono due puntatori inutilizzati: con il metodo SUPER verrà invocato il metodo dell'oggetto precedente, in modo da poter accedere effettivamente ai dati desiderati (nel nostro caso, otterremo i puntatori alla bitmap e alla palette di "immagine").
Un'altra caratteristica degli oggetti che ne ereditano degli altri è la loro possibilità di "ridefinire" dei metodi degli oggetti precedenti. La ridefinizione è uno strumento molto potente che permette a oggetti "simili" di comportarsi in modo completamente differente tra loro. Questa caratteristica, unita con il comando SUPER permette effettivamente di semplificare e migliorare notevolmente il comportamento di oggetti precedenti... o semplicemente di migliorare il nostro codice.
Tornando al nostro esempio precedente, potevamo ridefinire i metodi bitmap() e cols() dell'oggetto "remapper" in questo modo:
bitmap() OF remapper IS SUPER self.bitmap() - Chiamiamo bitmap() di "immagine" cols() OF remapper IS SUPER self.cols() - Chiamiamo cols() di "immagine"
E in questo modo potevamo definire remap() in questo modo:
remap IS self.makeremap(self.bitmap(), self.cols(), pal)Naturalmente, questo è un esempio abbastanza inutile e poco significativo, ma cercheremo di farne di più interessanti più avanti.
INHERITANCE (Ereditarietà): un oggetto può ereditarne un altro e sfruttare tutte le caratteristiche proprie dell'oggetto originale. In Amiga E la sintassi è la seguente:
OBJECT nuovo_oggetto OF vecchio_oggetto definizione del nuovo oggetto ENDOBEJCT
METHODS REDEFINITIONS (ridefinizione dei metodi): un oggetto creato su di un altro, ne può ridefinire i metodi e i comportamenti in maniera del tutto trasparente.
La sintassi in Amiga E è la seguente:
PROC nome_metodo() OF nuovo_oggetto nuovo codice .... nuovo codice ENDPROC
SUPER: è un comando particolarmente interessante perchè rende possibile invocare un metodo dell'oggetto originario dal nuovo oggetto. La sintassi in Amiga E è questa:
SUPER self.metodo() -> chiama metodo() di vecchio_oggetto.
Per guardare l'esempio premete qui.
Buono studio del sorgente!
Scritto da: Fabio Rotondo e-mail: fsoft@intercom.it C.so Vercelli 9 28100 Novara ITALY tel: (ITA) - (0)321 459676