Home
Accesso / Registrazione
 di 

Programmazione orientata agli oggetti in ANSI-C. Funzioni per gli oggetti - Implementazione 1/2

Programmazione orientata agli oggetti in ANSI-C. Funzioni per gli oggetti - Implementazione

Come eccezione, _Object deve essere il nome di una struttura e non un puntatore alla struttura, tanto che &_Object può essere utilizzato per inizializzare la struttura. Se non introduciamo un macro come Class(), c'è poca differenza, ma andiamo a complicare un po' il nostro programma munch.

NF != 3 || $1 !˜ /ˆ[0—9a—f]+$/ { next }
$2 ˜ /ˆ[bs]$/ { bsd[$3] = 1; next }
$2 == "d" { sysv[$3] = 1; next }
$2 == "T" { T[$3] = 1; next }
END {
for (name in T)
if ("_" name in bsd) # eliminate leading _
names[n ++] = substr(name, 2)
else if ("_" name in sysv)
names[n ++] = name
for (i = 0; i < n; ++ i)
printf "extern const void * %s (void);\n", names[i]
print "\nconst void * (* classes [])(void) = {"
for (i = 0; i < n; ++ i)
printf "\t%s,\n", names[i]
print "0 };"
}

Il nome di una classe dovrebbe comparire come funzione globale e con un underscore che precede il nome. L'utility Berkeley-nm inizializza i dati locali con una s e i dati non inizializzati con b. L'utility nm di System V usa d in entrambi i casi. Possiamo semplicemente raccogliere tutti i simboli interessanti nei tre array e confrontarli con la clausola END per produrre l'array names[] di cui abbiamo bisogno. Vi è inoltre un piccolo vantaggio in questa architettura: possiamo inserire un semplice shellsort per produrre i nomi delle classi in ordine alfabetico.

for (gap = int(n/2); gap > 0; gap = int(gap/2))
for (i = gap; i < n; ++ i)
for (j = i—gap; j >= 0 && \
names[j] > names[j+gap]; j —= gap)
{ name = names[j]
names[j] = names[j+gap]
names[j+gap] = name
}

Se usiamo chiamate alle funzioni al posto dei nomi delle classi non abbiamo bisogno di munch, tutavia una lista delle classi in un programma può essere utile per altri e futuri scopi.

Riepilogo

gli oggetti statici come le descrizioni di classe saranno tipicamente inizializzate al tempo di compilazione. Se abbiamo bisogno di chiamate ai costruttori, dobbiamo gestrili attraverso funzioni con parametri e assicurarci che queste funzioni siano chiamate sufficientemente presto nel programma e nell'ordine corretto. Per evitare problemi durante la diagnostica degli errori, dobbiamo fornire un meccanismo che realizza queste chiamate alle funzioni automaticamente – i nostri programmi devono essere auto-organizzanti.

Una soluzione consiste nell'usare la tecnica di linking, per esempio con l'aiuto di un programma come munch, produrre un array con gli indirizzi di tutte le funzioni di inizializzazione e chiamare ogni elemento dell'array all'inizio del programma principale. Una funzione main() che con un ciclo esegue l'array può essere parte della nostra libreria di progetto e ogni programma inizierà con una funzione mainprog() che sarà a sua volta chiamata da main().

Esercizi

La macro Class() è una soluzione più efficiente e portabile per l'inizializzazione automatica di descrizioni di classi piuttosto che usare le funzioni. Viene implementata tramite report modificabili, definizioni di classe e programmi applicativi così come descritto nei paragrafi precedenti.

Munch deve essere portato all'interno di un nuovo sistema. Se venisse usato assieme alla macro Class() per un sistema di produzione potremmo rimuovere la condizione dalla macro e inizializzare tutte le descrizioni di classe con munch. Come inizializziamo il tutto nel giusto ordine? Può ooc essere usato per aiutare in questo caso (consultare il manuale in appendice C circa l'opzione -M)? Che cosa fare con cast() in un sistema di produzione?

Tutte le descrizioni di classe dovrebbero chiamare dapprima cast(). Se definiamo una classe fittizia:

typedef const void * (* initializer) (void);
% Class ClassInit: Object {
initializer init;
%}

e usiamo le istanze inizializzate staticamente come descrizioni di classe non inizializzate

static struct ClassInit _Point = {
{ MAGIC, 0 }, /* Object without class description */
initPoint /* initialization function */
};
const void * Point = & _Point;

cast() può ora scoprire una descrizione di classe con un puntatore nullo alla descrizione di classe, ipotizzare che è una struct ClassInit e chiamare la funzione di inizializzazione. Mentre questa soluzione riduce il numero di chiamate a funzioni non necessarie, come influenza invece l'uso di cast()?

 

 

Scrivi un commento all'articolo esprimendo la tua opinione sul tema, chiedendo eventuali spiegazioni e/o approfondimenti e contribuendo allo sviluppo dell'argomento proposto. Verranno accettati solo commenti a tema con l'argomento dell'articolo stesso. Commenti NON a tema dovranno essere necessariamente inseriti nel Forum creando un "nuovo argomento di discussione". Per commentare devi accedere al Blog

 

 

Login   
 Twitter Facebook LinkedIn Youtube Google RSS

Chi è online

Ci sono attualmente 3 utenti e 8 visitatori collegati.

Ultimi Commenti