Programmazione orientata agli oggetti in ANSI-C. Linking Statico e Dinamico

Una sottoclasse eredita i metodi linkati staticamente della sua superclasse e può scegliere di ereditare, sovrascrivere i metodi linkati dinamicamente. Considerate per esempio le dichiarazioni di move() e draw()

void move (void * point, int dx, int dy);
void draw (const void * self);

Non si può scoprire i collegamento fra le due dichiarazioni, sebbene l'implementazione di move() compia il lavoro direttamente, mentre draw è la sola funzione selettore che traccia il dynamic linkage al momento dell'esecuzione. La sola differenza è che si dichiara un metodo staticamente linkato come move() come parte dell'interfaccia del tipo di dato astratto in Point.h e dichiariamo un metodo dinamicamente collegato come draw() con l'interfaccia per la gestione della memoria in new.h perchè si è deciso di implementare la funzione selettore in new.c

Il linkage statico è più efficiente perchè il compilatore C può codificare una chiamata ad una subroutine con un indirizzo diretto, ma una funzione come move() può essere sovrascritta in una sottoclasse. Il dynamic linkage è più flessibile a spese di una chiamata indiretta – si decide pertanto di accettare l'overhead di una chiamata a una funzione selltore come draw(), controllando quindi gli argomenti, localizzando e chiamando i metodi appropriati. Potremmo ridurre l'overhaead con una macro come

#define draw(self) \
	(( * (struct Class **) self) -> draw(self))

ma le macro possono causare problemi se i loro argomenti avessero degli effetti indesiderati. Inoltre non esiste una tecnica pulita ed elegante per gestire la lista di argomenti con le macro. In più, la macro necessita la dichiarazione di struct Class che abbiamo pocanzi reso disponibile non all'intera applicazione. Sfortunatamente, molte cose non vengono decise al momento di progettare la superclasse. Mentre la funzione che chiama il metodo non cambia, è necessario effettuare un bel po' di text editing, con la possibilità di scrivere un sacco di classi, di cambiare la definizione di una funzione da statica a dinamica e viceversa. All'inizio del capitolo 7 useremo un semplice processore per semplificare la codifica, ma non si è esenti da errore neanche in questo caso.

In caso di dubbio è probabilmente meglio decidere favorendo il dynamic linkage piuttosto che lo static linkage, anche se è meno efficiente. Le funzioni generiche possono provvedere a fornire un'astrazione concettuale molto utile e tendono a ridurre il numero di nomi di funzioni che è necessario ricordare nel corso di un progetto. Se, dopo aver implementato tutte le classi necessarie, si scopre che un metodo linkato dinamicamente non è stato sovrascritto, è molto meno oneroso rimpiazzare il suo selettore con la sua implementazione e persino sprecare spazio in struct Class piuttosto che estendere la descrizione di tipo e correggere tutte le inizializzazioni.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend