Ebbene sì! Anche con FreeBASIC possiamo adottare nei nostri programmi il paradigma della programmazione orientatata agli oggetti.
In inglese: object-oriented programming (OOP).
Classe
Il costrutto della classe lo realizzaremo in FreeBASIC attraverso un tipo di dato definito da noi (user-defined type o UDT) che utilizzeremo quindi come modello per creare i nostri oggetti.
Oggetto
Per poter creare un oggetto a partire da una classe – ovvero, in FreeBASIC, dal tipo di dato definito da noi – questa dovrà contenere tra i suoi membri, oltre alle proprietà (variabili, costanti, array, ecc.) e ai metodi (subroutines e funzioni), anche delle particolari procedure chiamate costruttore e distruttore.
Si usa dire che un oggetto è una istanza di una classe.
Costruttore e Distruttore
Quando viene definito un nuovo oggetto, il compilatore FreeBASIC chiamata automaticamente la procedura costruttore di default che inizializza i valori dei parametri dell’oggetto.
Quando invece viene eliminato un oggetto, il compilatore FreeBASIC chiama automaticamente la procedura distruttore che libera le risorse del sistema precedentemente utilizzate dall’oggetto.
Un oggetto viene implicitamente distrutto ogni volta che viene passato per valore in una procedura o quando esce dal suo ambito di utilizzo.
Per dichiarare una certa procedura come costruttore del nostro oggetto utilizzeremo l’istruzione constructor, mentre per la procedura distruttore utilizzeremo l’istruzione destructor.
A differenza delle procedure sub o function, per il costruttore e il distruttore non è necessario specificare alcun nome.
In una classe possiamo specificare più costruttori, ma un solo distruttore.
Quando invece copiamo o creiamo un clone di un oggetto a partire da un oggetto dello stesso tipo il compilatore FreeBASIC crea automaticamente anche il costruttore per la copia o la clonazione.
Queste due tipologie di costruttore possono però anche essere dichiarate e definite dallo stesso programmatore; il quale può, inoltre, anche dichiarare e definire eventuali altri costruttori “specializzati”.
Vediamo ora un po’ più in dettaglio alcune caratteristiche di queste diverse tipologie di costruttori.
Costruttore di default
Il costruttore di default è una procedura che non riceve argomenti e quindi eventuali parametri al suo interno avranno dei valori già impostati da noi o, se non li abbiamo impostati, avranno dei valori di default (p.e. le variabili numeriche avranno valore zero). Questo costruttore viene invocato dal compilatore FreeBASIC appena si definisce un oggetto.
Costruttore per le copie o i cloni degli oggetti
Questo costruttore viene invocato automaticamente dal compilatore FreeBASIC quando viene creato o clonato un oggetto da parte di un altro oggetto dello stesso tipo, oppure quando viene passato ad una procedura per valore (byval). Per dichiarare questo tipo di costruttore occorre che nella dichiarazione sia previsto come argomento un oggetto dello stesso tipo passato per riferimento.
Costruttore “specializzato”
Come programmatori, possiamo definire uno o più di questo tipo di costruttore quando, per esempio, abbiamo la necessità di passare dei valori specifici come argomenti in fase di creazione dell’oggetto.
Esempio dei tre tipi di costruttore e del distruttore
type poligono_regolare
declare constructor
declare constructor(byref p as poligono_regolare)
declare constructor(n as integer)
declare destructor
dim numero_lati as integer
end type
''definizione della procedura costruttore di default
constructor poligono_regolare
numero_lati = 3
end constructor
''definizione della procedura costruttore per le copie o i cloni
constructor poligono_regolare(byref p as poligono_regolare)
numero_lati = p.numero_lati
end constructor
''definizione della procedura per un costruttore "specializzato"
constructor poligono_regolare(n as integer)
numero_lati = n
end constructor
''definizione della procedura distruttore
destructor poligono_regolare
''istruzioni per la distruzione (vedi istruzione delete) per esempio
''di eventuali altri oggetti utilizzati all'interno dell'oggetto.
end destructor
Proprietà
Come abbiamo visto, a partire da una classe possiamo creare (istanziare) più oggetti. Quando creiamo degli oggetti, è molto probabile che ci interessi caratterizzarli con differenti proprietà. Rimanendo nell’esempio della classe “poligono_regolare”, magari vorremmo creare diversi poligoni regolari (oggetti) con la proprietà “colore” differente. Nella programmazione ad oggetti è bene mantenere privato l’ambito di utilizzo delle proprietà: in modo tale che non sia possibile accederci direttamente dall’esterno. Per modificarne il valore, o per leggerlo, scriveremo delle procedure ad hoc che ci garantiscano anche un maggior controllo sull’input dell’utente e sul tipo di output.
Esempio sulle proprietà
type poligono_regolare
''[...]
declare property colore(byref c as ulong) ''per impostare il valore del colore
declare property colore() as ulong ''per ottenere il valore del colore
private:
dim mio_colore as ulong
end type
property poligono_regolare.colore(byref c as ulong)
this.mio_colore = c
end property
property poligono_regolare.colore() as ulong
return this.mio_colore
end property
Nota sul parametro this
Nell’esempio riportato più sopra abbiamo fatto uso della parola-chiave this.
Questa parola-chiave è un argomento nascosto passato per riferimento che funge appunto da riferimento ad uno specifico oggetto (ovvero alla specifica istanza di una classe). Questo riferimento viene automaticamente passato a tutti i membri dichiarati nella classe: costruttori, distruttore, proprietà, metodi (subroutines e funzioni) in modo tale che le loro definizioni potranno agire su quello specifico oggetto.
Metodi
Come per i costruttori e il distruttore, anche per i metodi, che in ultima analisi non sono altro che delle procedure di tipo sub o function, occorre che siano dichiarati all’interno della classe e definiti all’esterno.
Esempio di metodi
type poligono_regolare
''[...]
declare sub angolo_al_centro(n as integer)
declare function tipo(n as integer) as string
''[...]
dim angolo as long
end type
sub poligono_regolare.angolo_al_centro(n as integer)
angolo = 360/n
print "Angolo al centro: "; angolo
end sub
function poligono_regolare.tipo(n as integer) as string
select case n
case 3
return "triangolo equilatero"
case 4
return "quadrato"
case 5
return "pentagono regolare"
case else
return "non gestito"
end select
end function
Come creare un oggetto e una sua copia
Ora che abbiamo le basi per scrivere una classe, vediamo come creare il nostro primo oggetto e come da questo fare una sua copia.
''Definisce la CLASSE
type poligono_regolare
declare constructor() ''costruttore di default
declare constructor(byref p as poligono_regolare) ''costruttore per copia/clone
declare property numero_lati(byref n as integer) ''per impostare/cambiare
''il numero dei lati
declare property numero_lati() as integer ''per ottenere il numero dei lati
private:
dim num_lati as integer
end type
constructor poligono_regolare
num_lati = 3
end constructor
constructor poligono_regolare(byref p as poligono_regolare)
num_lati = p.num_lati
end constructor
property poligono_regolare.numero_lati(byref n as integer)
this.num_lati = n
end property
property poligono_regolare.numero_lati() as integer
return this.num_lati
end property
''------------------------------
''Dimensiona e crea un nuovo OGGETTO (una istanza della CLASSE)
dim poligono_a as poligono_regolare
print poligono_a.numero_lati ''stampa il valore di default 3
poligono_a.numero_lati = 6 ''cambia il numero dei lati
''Crea una copia
dim poligono_b as poligono_regolare
print poligono_b.numero_lati ''stampa il valore di default 3
poligono_b = poligono_a ''crea la copia
print poligono_b.numero_lati ''stampa il valore 6
Bene! Come introduzione alla programmazione orientata agli oggetti in FreeBASIC possiamo fermarci qui. 🙂
Nel prossimo articolo vedremo come lavorare con le proprietà di tipo stringa o array a lunghezza variabile.