Next Previous Contents

3. Uso

3.1 Uso Generale

Per compilare un programma C++ con questa libreria devi aggiungere lo switch

-I /usr/src/classlib
alla linea di comando del tuo compilatore C++ e
-lclasslib
alla linea di comando del linker.

La classlib e' una shared libray e puo' essere inclusa in formato binario nei tuoi programmi.

Gli include

Per poter utilizzare la libreria all'interno dei programmi C++ e' stato realizzato un metodo semplice per l'inclusione degli header; tutte le componenti della libreria possono essere incluse in un programma utilizzando l'include del file usclslib.h. Questo file a sua volta include tutte le componenti necessarie e nel corretto ordine, secondo la dichiarazione di una serie di simboli che controllano l'inclusione.

#define _Use_Arrays     // per l'uso degli array (TArray, TIArray, TSArray...)
#define _Use_FixString  // per l'uso di FixedString
#define _Use_SQueues    // per l'uso di TSIQueue
#define _Use_Prop       // per l'uso di PropertyContainer
#include <usclslib.h>
...
...
TArray<FixedString> arStrings(10,0,10);
...
...

Una ispezione del file usclslib.h e' necessaria per il corretto uso della libreria.

3.2 Le classi container

Le classi container rappresentanto il corpo principale della libreria. Un nutrito numero di container coprono all'incirca qualsiasi esigenza per la scrittura di programmi in C++.

Ogni oggetto che si voglia inserire nelle classi container deve possedere un valido operatore == per le funzioni di base della libreria. La funzione Find() principalmente usa questo operatore.

Le versioni sortate degli array (TSArray e TISArray) richiedono anche un operatore < per poter riconoscere un ordine fra gli oggetti inseriti.

Per poter utilizzare le forme dirette dei container e' richiesto inoltre che esista un valido operatore = per copiare dati fra le istanze degli oggetti.

In generale per ogni tipo di container due forme sono presenti: diretto e indiretto.

Container diretti

Le classi container dirette mantengono copie di istanze degli oggetti. Questo significa che deve esistere un operatore di copia (operator=) per poter leggere e inserire i dati nei container.

...
// questo va bene: tutti i tipi base hanno operator= e operator==
TArray<double> arDbl(100, 0, 10);
arDbl.add(123.45);
...
...
class myClass
{
public:
        int var1, var2, var3;
        myClass& operator=(const myClass& c) {
                var1 = c.var1;
                var2 = c.var2;
                var3 = c.var3;
                return *this;
        }

        int operator==(const myClass& c) const { return &c == this; }
};
...
...
TArray<myClass> arMC(10, 0, 10);

myClass c1;
c1.var1 = 10;
c1.var2 = 20;
c1.var3 = 30;
...
// inserice una istanza (NON UN POINTER) nell'array
// l'entry dell'array sara' copiata dall'oggetto c1 tramite l'operatore =
arMC.add(c1);
...
...

Container indiretti

I container indiretti mantengono puntatori a oggetti del tipo dichiarato. Un pointer ha sempre una sematica di copia, assicurata dal compilatore, per cui non e' necessario definire un operator= in questo caso.

...
class myClass
{
public:
        int var1, var2, var3;

        int operator==(const myClass& c) const { return &c == this; }
};
...
...
TIArray<myClass> arMC(10, 0, 10);

myClass c1 = new myClass;
c1->var1 = 10;
c1->var2 = 20;
c1->var3 = 30;
...
// inserisce il puntatore nell'array
// NON CHIAMARE delete SUL PUNTATORE c1
arMC.add(c1);
...
...

Ogni container indiretto supporta un concetto di appartenenza degli oggetti in esso contenuti. Se l'appartenenza e' attiva (questo e' il default per tutti i container indiretti) alla distruzione del container verranno distrutti tutti gli oggetti in esso contenuti, chiamando l'apposito operatore delete. Il comportamento di default puo' essere cambiato utilizzando il metodo

OwnsElements(int own)
Se 'own' e' zero l'appartenenza viene disattivata, alrimenti attivata.

Le funzioni comuni

In tutte (o quasi) le classi container sono implementate le queste funzioni:

        GetItemsInContainer()   ritorna il numero di oggetti nel container
        IsEmpty()               ritorna vero se il container e' vuoto
        ForEach()               auto iteratore per tutti gli oggetti contenuti
        FirstThat()             auto iteratore per la ricerca di un elemento
        LastThat()              auto iteratore per la ricerca di un elemento
        Flush()                 svuota il container

Gli auto iteratori sono particolarmente comodi per eseguire dei task per gli elementi contenuti nei container.

ForEach

La funzione 'void ForEach( IterFunc iter, void *args )' consente di eseguire una operazione su tutti gli elementi contenuti nel container. Il primo parametro e' una funzione del tipo 'void IterFunc(T&, void *);' che viene chiamata per ogni elemento dell'array passato come primo parametro. Il secondo parametro e' un puntatore ad un dato qualsiasi.

...
class myClass
{
public:
        int var1, var2, var3;

        int operator==(const myClass& c) const { return &c == this; }
};
...
...
TIArray<myClass> arMC(10, 0, 10);
...
...
void PutValues(myClass& c, void* args)
{
        c.var1 = c.var2 = c.var3 = *((int*)(args));
}
...
...
int val = 0;
arMC.ForEach(PutValues, &val);
...
...

ATTENZIONE: se la funzione di iterazione viene dichiarata all'interno di una classe DEVE essere dichiarata static.

FirstThat, LastThat

La funzione 'T *FirstThat( CondFunc cond, void *args ) const' consente di definire un confronto ad hoc per la ricerca del primo elemento nell'array che la soddisfi. In modo analogo 'T *LastThat( CondFunc cond, void *args ) const' ritorna l'ultimo elemento del container. Entrambe le funzioni utilizzano come primo parametro una funzione con un prototipo del tipo 'int CondFunc(const T&, void *);'.

...
class myClass
{
public:
        int var1, var2, var3;

        int operator==(const myClass& c) const { return &c == this; }
};
...
...
TIArray<myClass> arMC(10, 0, 10);
...
...
int searchEqualValues(const myClass& c, void* args)
{
        return c.var1 == *((int*)(args));
}
...
...
int val = 0;
myClass* ptMy = arMC.FirstThat(searchEqualValues, &val);
if(ptMy != NULL) {
        // ptMy punta al primo elemento che soddisfa la condizione var1 == 0
        ...
}
...
...
int val = 0;
myClass* ptMy = arMC.LastThat(searchEqualValues, &val);
if(ptMy != NULL) {
        // ptMy punta all'ultimo elemento che soddisfa la condizione var1 == 0
        ...
}
...
...

ATTENZIONE: se la funzione di iterazione viene dichiarata all'interno di una classe DEVE essere dichiarata static.

Gli iteratori

Per ogni classe container esiste un equivalente iteratore per scorrere gli elementi contenuti nel container. Il nome della classe iteratore e' lo stesso della classe container con l'aggiunta di 'Iterator' alla fine. Ogni iteratore ha un operatore int che ritorna diverso da zero fino a quando ci sono elementi da iterare e un operatore ++ per avanzare all'elemento successivo. Un metodo Current() restituisce l'elemento corrente dell'iterazione. Un metodo Restart() fa ripartire l'iterazione dal primo elemento.

...
class myClass
{
public:
        int var1, var2, var3;

        int operator==(const myClass& c) const { return &c == this; }
};
...
...
TIArray<myClass> arMC(10, 0, 10);
...
...
TIArrayIterator<myClass> itrMC(arMC);
while(itrMC) {
        const myClass* c = itrMC.Current();
        ...
        ...
        itrMC++;
}
...
...
for(itrMC.Restart() ; itrMC ; itrMC++)
{
        const myClass* c = itrMC.Current();
        ...
        ...
}
...
...

3.3 Altre classi di utilita.

Una serie di classi di utilita' offrono una serie di semplici soluzioni a problemi frequenti nella programmazione:

1) PropertyContainer  lettura/scrittura di parametri da file di configurazione (chiave=valore).
2) Funzioni template  per uso generale.
3) Socket             comunicazioni client/server TCP, UDP, UNIX domain socket.
4) Multitask          semplice implementazione di mutex, semafori, ecc. per la programmazione multitask.

PropertyContainer.

La classe PropertyContainer implementa il reperimento di valore associato a chiave. Essa consente di gestire facilemente file di configurazione in formato ASCII, potendo leggere direttamente un file formattato secondo la classica sintassi UNIX dei files di configurazione.

La classe PropertyContainer utilizza un dizionario con tabella di hashing per l'implementazione.

#
# QUESTO E' IL MIO FILE DI CONFIGURAZIONE (/etc/mio.conf)
#

# imposta il valore della proprita' host e port
host=www.winada.it
port=8080

Questo file puo' essere letto cosi':

PropertyContainer p;
p.loadFile("/etc/mio.conf");

FixString hostName = p.getProperty("host", "localhost");
int port = p.getPropertyInt("port", 7000);
...
...

Funzioni template.

Una serie di comode funzioni template per ottenere il massimo, il minimo (anche fra tre valori) e similari sono presenti nel file stdtempl.h. Vedi il file per ulteriori dettagli.

Socket.

Vedi l'apposita sezione piu' avanti.

Multitask.

Nella programmazione multithread sono necessari alcuni oggetti comunemente noti com mutex, semafori, eventi. Per ognuno di questi esiste una apposita classe illustrata piu' avanti con specifiche caratteristiche.

3.4 Classi e funzioni matematiche.

Una corposa parte della libreria racchiude una serie di funzioni matematiche implementate sotto forma di classi di oggetti, per la manipolazione di dati e strutture geometriche in 2D e 3D.

Le classi Punto2D e Punto3D implementano un concetto di punto nello spazio bidibmensionale e tridimensionale. Le Linea2D e Linea3D rappresentano un concetto di linea nello spazio 2D e 3D. La classe Matrix3 viene utilizzata per elaborare le trasformazioni (calcolo matriciale) da applicare ai punti e alle linee.

Vedi l'apposita sezione per i dattagli.


Next Previous Contents