Programmazione orientata agli oggetti in ANSI-C. Funzioni per gli oggetti

munch è una soluzione portabile anche se inefficiente per tutto quello che può riguardare i problemi di inizializzazione statica.

Costruire descrizioni di classe prima che esse vengano usate è abbastanza semplice e ne consegue che vi è una maniera molto più rapida e completamente portabile per ottenere una soluzione al problema.

Il nostro problema consiste nel fatto che usiamo una variabile puntatore per fare riferimento ad un oggetto ma abbiamo bisogno di chiamare una funzione per creare l'oggetto se esso non esiste già. Ciò determina la definizione della seguente macro:

#define Point (Point ? Point : (Point = initPoint()))

La macro Point verifica se la descrizione della classe Point è già stata inizializzata. Se non lo è, chiama InitPoint() per generare la descrizione di classe. Sfortunatamente, se definiamo Point come macro senza parametri non possiamo riusare tale nome per la struttura o per gli oggetti oppure per la descrizione di classe. La macro seguente è migliore in questo senso.

#define Class(x) (x ? x : (x = init ## x ()))

Ora, specifichiamo Class(Point) per fare riferimento alla descrizione di classe. InitPoint() chiama ancora new() come faceva prima ma ora deve restituire la descrizione di classe generata, ossia ogni descrizione di classe deve avere la sua funzione di inizializzazione.

const void * Point;
const void * initPoint (void) {
return new(Class(PointClass),
"Point", Class(Object), sizeof(struct Point),
ctor, Point_ctor,
draw, Point_draw,
(void *) 0);
}

Questa modalità di affrontare il problema impone ancora di osservare l'ordine imposto dalla gerarchia delle classi: prima la descrizione di classe PointClass viene passata a new(), l'espansione della macro Class(PointClass) si assicura che la descrizione esista. L'esempio mostra che per uniformità dobbiamo fornire le funzioni vuore InitObject() e InitClass().

Se ogni funzione di inizializzazione restituisce l'oggetto inizializzato, lo possiamo fare con macro e chiama semplicemente le funzioni di inizializzazione ogni qualvolta vogliamo accedere all'oggetto – un oggetto statico è rappresentato dalla sua funzione di inizializzazione:

static const void * _Point;
const void * const Point (void) {
return _Point ? _Point :
(_Point = new(PointClass(),
"Point", Object(), sizeof(struct Point),
ctor, Point_ctor,
draw, Point_draw,
(void *) 0));
}

Potremmo spostare la definizione del puntatore corrente _Point all'interno della funzione, tuttavia la definizione globale è necessaria se vogliano ancora implementare munch per System V.

Sostituire gli oggetti statici da funzioni non deve essere meno efficiente che usare le macro. L'ANSI-C non permette la dichiarazione di un risultato const oppure volatile per una funzione. Il GNU-C ammette tale dichiarazione e la sfrutta durante l'ottimizzazione. Se una funzione ha un risultato const il suo valore deve dipendere solo dai suoi argomenti e la chiamata non deve produrre dei side-effects. Il compilatore cerca di minimizzare il numero di chiamate a tali funzioni e riutilizza i risultati.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend