Programmazione orientata agli oggetti in ANSI-C. Implementazione della superclasse – Punto

L'interfaccia di dato astratto in Point.h contiene le seguenti linee:

extern const void * Point; /* new(Point, x, y); */
void move (void * point, int dx, int dy);

Possiamo riciclare i file di new.? Illustrati in un altro articolo con la differenza di eliminare molti metodi e di aggiungere draw() in new.h.

void * new (const void * class, ...);
void delete (void * item);
void draw (const void * self);

La descrizione di tipo struct Class in new.r dovrebbe corrispondere alle dichiarazioni dei metodi in new.h

struct Class {
size_t size;
void * (* ctor) (void * self, va_list * app);
void * (* dtor) (void * self);
void (* draw) (const void * self);
}

Il selettore draw() viene implementato in new.c il quale rimpiazza i selettori quali differ() introdotti nella sezione 2.3. draw() viene codificato nello stesso stile del differ()

void draw (const void * self)
{ const struct Class * const * cp = self;
assert(self && * cp && (* cp) —> draw);
(* cp) —> draw(self);
}

Dopo queste considerazioni preliminare, possiamo occuparci del vero lavoro, ossia di scrivere praticamente il file Point.c che altro non è che l'implementazione di punti. Ancora una volta, lavorando in maniera orientata agli oggetti ci ha aiutato ad identificare precisamente ciò che dobbiamo fare: dobbiamo decidere sulla rappresentazione e sull'implementazione di un costruttore, un distruttore, del linkage dinamico di draw() e del metodo invocato staticamente move(). Se ipotizziamo di lavorare in un ambiente bidimensionale, basato sulle coordiante cartesiane, possiamo quindi scegliere la facile rappresentazione:

struct Point {
const void * class;
int x, y; /* coordinates */
};

Il costruttore deve inizializzare le coordinate .x e .y – cosa che è praticamente la solita routine

static void * Point_ctor (void * _self, va_list * app)
{ struct Point * self = _self;
self —> x = va_arg(* app, int);
self —> y = va_arg(* app, int);
return self;
}

Non avremo bisogno di un distruttore perchè non abbiamo risorse da reclamare prima che entri in gioco la funzione delete(). In Point_draw() stampiamo le coordinate correnti in un modo che pic può comprendere:

static void Point_draw (const void * _self)
{ const struct Point * self = _self;
printf("\".\" at %d,%d\n", self —> x, self —> y);
}

Questo codice seguente invece si prende cura di tutti i metodi linkati dinamicamente e possiamo definire il descrittore di tipo, dove un puntatore nullo rappresenta il distruttore (che non esiste)

static const struct Class _Point = {
sizeof(struct Point), Point_ctor, 0, Point_draw
};
const void * Point = & _Point;

move() non è linkato dinamicamente, così omettiamo static per esportarlo da Point.c e non precediamo il suo nome con il nome della classe Point

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

Ecco conclusa la implementazione dei punti in Point.? assieme al supporto per il dynamic linkage in new.?.

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend