Programmazione orientata agli oggetti in ANSI-C. Selettori, Dynamic Linkage e Polimorfismo 2/2

La parte critica sta certamente nell'ipotesi che si possa trovare un puntatore al descrittore di tipo *self direttamente al di sotto del puntatore arbitrario self. Per il momento ci limiteremo a vigilare che non vi siano puntatori nulli. Si potrebbe piazzare un numero magico all'inizio di ogni descrizione di tipo oppure confrontare *self con l'indirizzo o il range di indirizzi di tutte le descrizioni di tipo, ma vedremo nel capitolo 8 che potremmo effettuari controlli più rigorosi.

In ogni caso, differ() illustra perfettamente perchè questa tecnica di chiamata delle funzioni è detta dynamic linkage o anche late binding: mentre possiamo chiamare differ() per oggetti arbitrari finchè iniziano con un appropriato puntatore alla descrizione di tipo, la funzione che in effetti realizza il lavoro vero e proprio viene determinata il più tardi possibile - solo durante l'esecuzione della chiamata stessa e non prima.

Chiameremo differ() una funzione selettore. E' un esempio di funzione polimorfica, ossia di una funzione che può accettare argomenti di tipi diversi e comportarsi diversamente su di essi basandosi sul loro rispettivo tipo. Una volta che avremmo implementato più classi contenenti tutte .differ nei loro descrittori di tipo, differ() sarà una funzione generica che può essere applicata da ogni oggetti di queste classi.

Possiamo vedere i selettori come metodi che essi stessi non sono dinamicamente linkati ma si comportano già come funzioni polimorfiche perchè lasciano che funzioni dinamicamente linkate svolgano il "vero lavoro".

Le funzioni polimorfiche sono disponibili in molti linguaggi di programmazione, basti pensare alla procedura write() del Pascal che permette di utilizzare argomenti di tipi diversi in accordo appunto al loro tipo, oppure all'operatore + in C che ha un effetto diverso se viene utilizzato su interi, puntatori o valori floating point. Questo fenomeno viene anche chiamato overloading: i tipi degli argomenti assieme ai nomi degli operatori determinano ciò che l'operatore fa; lo stesso nome di operatore può essere usato con diversi tipi di argomenti per produrre effetti diversi.

Qui non c'è una chiara distinzione: per via del dynamic linkage, differ() si comporta come una funzione di cui è stato fatto un overload, e il compilatore C può fare in modo che + si comporti come una funzione polimorfica - almeno per quanto riguarda i tipi di dati già disponibili nel linguaggio. Comunque, il compilatore C può creare risultati di tipo diverso di fronte a usi diversi dell'operatore + ma la funzione differ() deve sempre avere lo stesso tipo di risultato indipendentemente dal tipo dei suoi argomenti.

I metodi possono essere polimorfici senza avere il dynamic linkage. Ad esempio, consideriamo la funzione sizeOf() che restituisce la dimensione di un qualsiasi oggetto:

size_t sizeOf (const void * self)
{ const struct Class * const * cp = self;
assert(self && * cp);
return (* cp) —> size;
}

Tutti gli oggetti dispongono del proprio descrittore e possiamo pertanto dal descrittore recuperarne la dimensione. Da notare che vi è una differenza fra:

void * s = new(String, "text");
assert(sizeof s != sizeOf(s));

sizeof è l'operatore C che viene valutato a tempo di compilazione e ritorna il numero di bytes che il suo argomento richiede. La funzione sizeOf() è la nostra funzione polimorfica che a tempo di esecuzione ritorna il numero di bytes dell'oggetto al quale l'argomento punta.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend