Programmazione orientata agli oggetti in ANSI-C. Codifica standard -1

L'idea base è chiamare cast() tutte le volte che è necessario. Quando un metodo staticamente linkato dereferenzia gli oggetti nella sua stessa classe, dovrebbe fare proprio questo;

void move (void * _self, int dx, int dy) {
struct Point * self = cast(Point, _self);
self —> x += dx, self —> y += dy;
}

Se tale metodo riceve gli oggetti da un'altra classe, può ancora operare un cast() per assicurarsi che i parametri sono proprio quelli che dichiarano di essere. Abbiamo introdotto la richiesta %casts nel preprocessore ooc per gestire l'importazione di una lista di parametri.

% move {
%casts
self —> x += dx, self —> y += dy;
}

%casts viene implementato con il report casts in etc.rep, di conseguenza possiamo controllare tutte le importazioni di oggetti andando a modificare questo report. La versione originale è illustrata nella sezione 7.4, qui introduciamo cast():

% casts // implement %casts request
`{() // import
`{if `_ _
`t `const struct `cast * `name = ` \
cast( `cast , _ `name ); `n
`}fi
`}n
`{if `linkage % // for static linkage only
`%checks
`}fi

La sostituzione di '_ è definita come un underscore se il parametro corrente si trova nella classe corrente. Invece di un normale assegnamento, chiameremo cast() per controllare prima di dereferenziare il puntatore.

Il primo ciclo in import si occupa di tutti gli oggetti coinvolti in un metodo della propria classe. Gli altri oggetti sono controllati nel report checks:

% checks // check all other object parameters
`{()
`{ifnot `cast ` `{ifnot `_ _
`t cast( `cast , `name ); `n
`}fi `}fi
`}n

Originariamente, questo ciclo genera assert() per tutti gli oggetti. Ora possiamo restringere il campo a quegli oggetti che non si trovano nella classe corrente. Per questi oggetti generiamo una chiamata a cast() per assicurarci che essi sono proprio della classe opportuna.

Il report casts tratta in maniera differente metodi con linking statico o dinamico. I metodi staticamente linkati devono effettuare i propri controlli. Casts e checks generano variabili locali per il derefenziamento e statement che vanno a controllare altri oggetti, ossia %casts deve essere usato alla fine della lista di variabili locali dichiarate all'inizio di un metodo con linking statico.

I metodi linkati dinamicamente sono chiamati esclusivamente tramite selettori, di conseguenza il lavoro di controllo può essere delegato ad essi stessi. %casts viene ancora usato per dereferenziare gli oggetti parametro nella classe corrente, ma inizializzerà solamente variabili locali:

Circle.dc
% Circle draw {
%casts
printf("circle at %d,%d rad %d\n",
x(self), y(self), self —> rad);
}

Point.c
void draw (const void * _self) {
const struct Point * self = _self;
...
Circle.c
static void Circle_draw (const void * _self) {
const struct Circle * self = cast(Circle, _self);
...

Dobbiamo essere attenti: mentre il selettore può controllare se un oggetto appartiene alla classe corrente Point, una volta che chiama il metodo della sottoclasse come Circle_draw() dobbiamo controllare se l'oggetto sia veramente un Circle.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend