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

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.

Leave a Reply