Programmazione orientata agli oggetti in ANSI-C. Riepilogo

Gli oggetti puntano alle loro descrizioni di classe che, per la maggior parte, contengono puntatori a metodi linkati dinamicamente. Le descrizioni di classe con lo stesso insieme di puntatori a metodi costituisce una metaclasse – le descrizioni di classe sono anch'esse oggetti. Una metaclasse, a sua volta, ha una descrizione di classe.

Si può pensare in termini finiti (e non in loop infinito) perchè ci possiamo appoggiare su una classe triviale chiamata Object e con una metaclasse iniziale Class che ha Object come superclasse. Se lo stesso insieme di metodi – costruttori, distruttori, metodi di confronto, metodi per la visualizzaizone delle informaioni – possono essere applicati agli oggetti e alle descrizioni di classe, allora la descrizione della metaclasse Class che descrive la descrizione di classe Object descrive anche sé stessa.

Un costruttore della metaclasse riempie una descrizione di classe e quindi implementa l'ereditarietà binaria, il distruttore ritorna zero per proteggere la descrizione di classe dalla eliminazione accidentale, le funzioni di visualizzazione potrebbero mostrare i puntatori ai metodi e così via.

Due descrizioni di classi sono identiche se e solo se i loro indirizzi sono identici. Se aggiungiamo metodi linkati dinamicamente come draw() dobbiamo creare una nuova metaclasse, perchè il suo costruttore è il solo che può inserire l'indirizzo di un metodo in una descrizione di classe. La descrizione della metaclasse usa sempre struct Class e viene di conseguenza creato da una chiamata come ad esempio la seguente:

PointClass = new(Class, ...
ctor, PointClass_ctor,
0);

Una volta che la descrizione della metaclasse esiste, possimao creare descrizioni delle classi in queste metaclassi e inserire il nuovo metodo.

Point = new(PointClass, ...
draw, Point_draw,
...
0);

Queste due chiamate possono essere eseguite esattamente una volta sola, prima che un qualsiasi oggetto nella nuova classe venga creato. Questo è un modo standard per scrivere tutti i costruttori delle metaclassi così che le coppie selettore/metodo possano essere specificate in un ordine qualsiasi. Più classi nella stessa metaclasse possono essere create semplicemente spedendo new() alla descrizione della metaclasse

I selettori sono inoltre scritti in modo standard. E' una buona idea decidere su una convenzione per i costruttori e i distruttori per gestire correttamente la catena delle superclassi. Per semplificare la codifica, conviene dotare i selettori della superclasse con gli stessi argomenti dei selettori; un ulteriore parametro iniziale deve essere specificato per specificare la classe per la quale la chiamata al metodo della superclasse viene definito. Anche i selettori delle superclassi sono scritti seguendo il criterio generale precedentemente esposto.

Uno stile coerente permette di rendere più semplice e robusta l'implementazione: i selettori verificano gli oggetti, la classe e l'esistenza di un metodo: i selettori della superclasse potrebbero verificare anche il nuovo argomento; un metodo dinamicamente linkato viene chiamato solamente attraverso un selettore,vale a dire non c'è la necessità di porre in verifica il suo oggetto. Un metodo staticamente linkato non è differente da un selettore: deve verificare il suo oggetto argomento.

Consentiteci ora di approfondire il significato di due componenti base di oggetti e di descrizioni di classe assieme alla nostra convenzione per assegnare i nomi. Ogni classe ha Object come superclasse. Dato un puntatore p ad un oggetto in una sottoclasse arbitraria di Object, il componente p->class punta alla descrizione di classe per l'oggetto. Ipotizziamo che il puntatore C punti alla stessa descrizione di classe e che C sia il nome della classe pubblicato nel file interfaccia C.h. Allora l'oggetto disponibile tramite p sarà rappresentato da una struct C. Questo spiega perchè nella sezione 6.3 Class->class deve puntare necessariamente a Class: l'oggetto al quale Class punta è rappresentato da una struct Class.

Ogni descrizione di classe deve iniziare con una struct Class per memorizzare informazioni quali il nome della classe o un puntatore alla descrizione della superclasse. Ora lasciamo che C punti a una descrizione di classe e lasciamo che C->super punti alla stessa descrizione di classe del puntatore S pubblicato nel file interfaccia S.h, ossia S è la superclasse di C. In questo caso, struct C deve iniziare con struct S. Questo spiega perchè nella sezione 6.3 Class->super deve puntare ad Object: abbiamo deciso che una struct Class inizia con una struct Object.

La sola eccezione ad questa regola si verifica in Object->super che ha il valore Object nonostante sia stato sottolineato nella sezione 6.3 che tale eccezione è il frutto di una decisione arbitraria.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend