Programmazione orientata agli oggetti in ANSI-C. Implementazione – seconda parte

respondsTo() deve cercare la descrizione di classe per un tag e restituire il corrispondente selettore. Di conseguenza, la descrizione di classe contiene solo puntatori ai metodi. Chiaramente l'entry del metodo in una descrizione di classe deve essere estesa:

typedef void (* Method) (); // for respondsTo()
%prot
struct Method {
const char * tag; // for respondsTo()
Method selector; // returned by respondsTo()
Method method; // accessed by the selector
};
% Class Object {
...
Method respondsTo (const _self, const char * tag);

Method è un tipo semplice di funzione definito nel file di interfaccia per Object. Ogni metodo è memorizzato in una descrizione di classe come componente del tipo struct Method che contiene i puntatori al tag, al selettore e al metodo corrente. RespondsTo() restituisce un Method.

Dato questa visione generale, sono però necessari alcune variazioni. In Object.dc abbiamo bisogno di cambiare l'inizializzazione statica delle descrizioni delle classi Object e Class per usare struct Method

static const struct Class _Object = {
{ MAGIC, & _Class },
"Object", & _Object, sizeof(struct Object),
{ "", (Method) 0, (Method) Object_ctor },
{ "", (Method) 0, (Method) Object_dtor },
{ "differ", (Method) differ,(Method) Object_differ },
...
};

Il report -r in r.rep usa il report link in va.rep per generare un entry nella descriozne di classe per il file di rappresentazione. La nuova versione del report link è molto molto semplice:

% link // component of metaclass structure
struct Method `method ;

Infine, il report init in c.rep e c-R.rep usa il metca-ctor-loop in etc.rep per generare il ciclo che dinamicamente riempie la descrizione di classe. Qui dobbiamo anche lavorare con i nuovi tipi:

% meta—ctor—loop // selector/tag/method tuples for `class
`t while ((selector = va_arg(ap, Method))) `n
`t { `t const char * tag = va_arg(ap, ` \
const char *); `n
`t `t Method method = va_arg(ap, Method); `n `n
`{%— `%link—it `}
`t } `n

% link—it // check and insert one selector/method pair
`t `t if (selector == (Method) `method ) `n
`t `t { `t if (tag) `n
`t `t `t `t self —> `method .tag = tag, `n
`t `t `t `t self —> `method .selector = selector; `n
`t `t `t self —> `method .method = method; `n
`t `t `t continue; `n
`t `t } `n

Piuttosto che le coppie selettore – metodo specifichiamo ora le tuple composte da selettore – tag – metodo come argomenti per il costruttore della metaclasse. Questo deve essere costruito nel report init in c.rep. Qui invece troviamo la funzione di inizializzazione che Wc genera tramite ooc:

static const void * _Wc;
const void * Wc (void) {
return _Wc ? _Wc :
(_Wc = new(WcClass(),
"Wc", Object(), sizeof(struct Wc),
wc, "line", Wc_wc,
printFile, "wrap", Wc_printFile,
printTotal, "quit", Wc_printTotal,
(void *) 0));
}

Date le tuple selettore tag metodo nella descrizione di classe, respondsTo() è facile da scrivere. Grazie alla gerarchia delle classi, possiamo calcolare quanti metodo una descrizione di classe contiene e possiamo implementare respondsTo interamente nella classe Object, anche se per sua natura si occupa di classi arbitrarie:

% respondsTo {
if (tag && * tag) {
const struct Class * class = classOf(_self);
const struct Method * p = & class —> ctor; // first
int nmeth =
(sizeOf(class) — offsetof(struct Class, ctor))
/ sizeof(struct Method); // # of Methods
do
if (p —> tag && strcmp(p —> tag, tag) == 0)
return p —> method ? p —> selector : 0;
while (++ p, —— nmeth);
}
return 0;
}

Il problema principale di questo approccio è che respondsTo() contiene esplicitamente il primo nome di metodo mai utilizzato e cioè ctor, che gli serve per calcolare il numero di metodi a partire dalla dimensione della descrizione di classe. Mentre ooc potrebbe ottenere questo nome dalla descrizione di classe di Object, potrebbe essere abbastanza complesso costruire un report per ooc in modo da generare respondsTo() con un approccio più generalistico.

Scarica subito una copia gratis

Una risposta

  1. Avatar photo @Facebook 20 Settembre 2010

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend