Programmazione orientata agli oggetti in ANSI-C. Selettori delle superclassi

Prima che un costruttore di una sottoclasse esegua la propria inizializzazione, è necessario che venga chiamato il costruttore della superclasse.

Analogamente, il distruttore della sottoclasse deve chiamare il distruttore della sua superclasse dopo che è stato completato il processo di richiamo delle risorse. Quando si implementano le funzioni selettore, dovrebbero essere forniti anche i selettori per le chiamate alle superclassi.

void * super_ctor (const void * _class,
void * _self, va_list * app)
{ const struct Class * superclass = super(_class);
assert(_self && superclass —> ctor);
return superclass —> ctor(_self, app);
}
void * super_dtor (const void * _class, void * _self)
{ const struct Class * superclass = super(_class);
assert(_self && superclass —> dtor);
return superclass —> dtor(_self);
}

Tali selettori dovrebbero essere chiamati solamente da una implementazione di una sottoclasse; quindi andiamo a includere le loro dichiarazioni nel file di rappresentazione e non nel file dell'interfaccia. Per stare nel sicuro, forniremo i selettori della superclasse per tutti i metodi linkati dinamicamente, ossia ogni selettore avrà un corrispondente selettore della superclasse. In questo modo ogni metodo linkato dinamicamente ha a disposizione una maniera semplicissima per chiamare il metodo della propria superclasse.

Attenzione però che potremmo trovarci di fronte a qualche piccolo problema. Consideriamo come un metodo di una classe arbitraria X può chiamare il metodo della superclasse. Questo è il modo corretto:

static void * X_method (void * _self, va_list * app)
{ void * p = super_method(X, _self, app);
...

Osservando i selettori della superclasse mostrati qui sopra vediamo che super_method() in questo caso chiama
super(X) —> method(_self, app);
ossia il metodo nella superclasse della classe X per il quale abbiamo appena definito X_method(). Lo stesso metodo viene raggiunto anche se qualche sottoclasse Y eredita il metodo X_method() perchè l'implementazione è indipendente da qualsiasi meccanismo di eredetarietà futura.

Il codice seguente per X_method() potrebbe sembrare più plausibile, ma non funzionerà quando il metodo sarà ereditato.

static void * X_method (void * _self, va_list * app)
{ void * p = /* WRONG */
super_method(classOf(_self), _self, app);
...

Il selettore della superclasse produce ora:
super(classOf(_self)) —> method(_self, app);

Se _self si trova nella classe X, raggiungeremo lo stesso metodo al pari della situazione precedente. Comunque, se _self è in una sottoclasse Y e X otterremo
super(Y) —> method(_self, app); e ciò è ancora il metodo X_method(), ossia invece di chiamare un metodo della superclasse otteniamo una sequenza di chiamate ricorsive, cosa che vogliamo accuratamente evitare.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend