Programmazione orientata agli oggetti in ANSI-C. Un’implementazione – String

Implementiamo le stringhe scrivendo i metodi che necessitano di essere inseriti nel descrittore di tipo String. Il dynamic linkage aiuta nell'identificare chiaramente quali funzioni devono essere "scritte" per implementare il nuovo tipo di dato.

Il costruttore recupera il testo passato a new() e memorizza una copia dinamica in struct String che è stata allocata da new():

struct String {
const void * class; /* must be first */
char * text;
};
static void * String_ctor (void * _self, va_list * app)
{ struct String * self = _self;
const char * text = va_arg(* app, const char *);
self —> text = malloc(strlen(text) + 1);
assert(self —> text);
strcpy(self —> text, text);
return self;
}

Nel costruttore abbiamo bisogno di inizializzare solamente .text perchè new() ha già impostato .class.

Il distruttore libera la memoria dinamica controllata dalla stringa. Poichè delete() può solo chiamare il distruttore se self non sia impostato a null, non dobbiamo fare ulteriori verifiche:

static void * String_dtor (void * _self)
{ struct String * self = _self;
free(self —> text), self —> text = 0;
return self;
}

String_clone() effettua una copia di una stringa. In seguito entrambe le stringhe, l'originale e la copia, saranno passate a delete() così che si possa creare una nuova copia dinamica del testo della stringa. Questo può essere fatto facilmente chiamando new():

static void * String_clone (const void * _self)
{ const struct String * self = _self;
return new(String, self —> text);
}

String_differ() è certamente falsa quando cerchiamo oggetti stringa identici ed è vera quando confrontiamo una stringa con oggetti completamente diversi. Se dobbiamo davvero confrontare due stringhe diverse, possiamo provare con strcmp():

static int String_differ (const void * _self, const void * _b)
{ const struct String * self = _self;
const struct String * b = _b;
if (self == b)
return 0;
if (! b || b —> class != String)
return 1;
return strcmp(self —> text, b —> text);
}

I descrittori di tipo sono unici - qui sfruttiamo questo concetto per scoprire se il nostro secondo argomento sia veramente una stringa.

Tutti questi metodi sono statici perchè dovrebbero chiamati solamente attraverso la funzione new(), delete() o altri selettori. I metodi resi disponibili ai selettori per mezzo del loro descrittore di tipo.

#include "new.r"
static const struct Class _String = {
sizeof(struct String),
String_ctor, String_dtor,
String_clone, String_differ
};
const void * String = & _String;

String.c include la dichiarazione pubblica in String.h e new.h. Per inizializzare propriamente il descrittore di tipo, include anche l'header privato new.r che contiene la definizione della rappresentazione di struct Class illustrata nel articolo: Programmazione orientata agli oggetti in ANSI-C. Metodi, Messaggi, Classi ed Oggetti

Scarica subito una copia gratis

Scrivi un commento

Seguici anche sul tuo Social Network preferito!

Send this to a friend