
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.
