Programmazione orientata agli oggetti in ANSI-C. Selettori

Programmazione orientata agli oggetti in ANSI-C. Selettori

Il lavoro di una funzione selettore non è cambiato da quanto illustrato nel capitolo 2. Un argomento _self è l’oggetto del linking dinamico. Verifichiamo che esso esista e che il metodo richiesto esista per l’oggetto.

Poi chiamiamo il metodo e passiamo tutti gli argomenti ad esso; di conseguenza il metodo può assumere che _self è l’oggetto adatto. Infine, restituiamo il valore che risulta dall’applicazione del metodo, se ce ne sono, come il risultato del selettore.

Ogni metodo linkato dinamicamente deve avere un selettore. Così, abbiamo nascosto le chiamate al costruttore e al distruttore dietro ai metodi new() e delete(), ma abbiamo ancora bisogno di ctor e dtor per le coppie selettore/metodo passate al costruttore Class. Potremmo decidere in futuro di effettuare il binding dinamico di new() e delete(). In questo caso non sarebbe una buona idea usare i loro nomi al posto di ctor e dtor.

Abbiamo introdotto una comune superclasse Object per tutte le nostre classi e abbiamo dato ad essa alcune funzionalità che semplificano l’implementazione delle funzioni selettore. ClassOf() ispeziona un oggetto e restituisce un puntatore non – zero alla sua descrizione di classe. Ciò permette di implementare delete() come segue:

void delete (void * _self)
{
if (_self)
free(dtor(_self));
}
void * dtor (void * _self)
{ const struct Class * class = classOf(_self);
assert(class —> dtor);
return class —> dtor(_self);
}

new() deve essere implementata in maniera attenta e precisa, ma in generale possiamo dire che lavora e si comporta come illustrato nel codice seguente:

void * new (const void * _class, ...)
{ const struct Class * class = _class;
struct Object * object;
va_list ap;
assert(class && class —> size);
object = calloc(1, class —> size);
assert(object);
object —> class = class;
va_start(ap, _class);
object = ctor(object, & ap);
va_end(ap);
return object;
}
/pre>
Verifichiamo quindi che la descrizione di classe sia corretta e facciamo in modo di essere sicuri di creare un oggetto inizializzato a 0. Procediamo poi ad inizializzare la descrizione di classe dell'oggetto e siamo pronti a lasciare che il normale selettore ctor() localizzi ed esegua il costruttore.
void * ctor (void * _self, va_list * app)
{ const struct Class * class = classOf(_self);
assert(class —> ctor);
return class —> ctor(_self, app);
}

Probabilmente i controlli da effettuare potrebbero sembrare eccessivamente numerosi, ma almeno siamo in grado di fornire sempre una interfaccia robusta ed uniforme.

Leave a Reply