Il modello a oggetti di Gambas

1. 1. Oggetti e classi

Un oggetto in Gambas è una struttura dati che fornisce proprietà, variabili, metodi ed eventi

Viene creato o istanziato usando l'operatore NEW, una classe che descrive l'oggetto (vedi 1.1) e gli argomenti opzionali per il costruttore di oggetti (vedi 1.5). Si accede agli oggetti "per riferimento", cioè usando un puntatore ad esso, o usando una variabile il cui valore è l'indirizzo della struttura dati dell'oggetto in memoria.

Puoi vedere l'indirizzo di un oggetto usando l'istruzione PRINT:
Dim aStr As New String[]

Print aStr
(String[] 0x80dccf8)

La struttura dei dati dell'oggetto è descritta dalla sua classe.

1.1. Classi

Ogni oggetto Gambas ha una classe che descrive tutte le sue proprietà, i metodi e gli eventi pubblici. Questa classe è anche un oggetto Gambas, la cui classe è la classe denominata Class.

Una classe statica è una classe i cui membri sono tutti statici (vedi sotto). In Gambas, una classe statica è anche denominata modulo.

Una classe statica non può essere istanziata: si creerebbe un oggetto senza alcuna variabile dinamica, cosa inutile.

Esempio

La classe System è una classe statica: tutti i suoi metodi sono statici e non è possibile creare un oggetto la cui classe sarebbe System.

Una classe virtuale è una pseudo-classe nascosta che non puoi manipolare esplicitamente.

1.2. Proprietà, metodi e variabili

Proprietà e metodi consentono di manipolare la struttura dei dati.

Un Proprietà, un Metodo o unVariabile possono essere statici:
  • Una variabile statica sarà condivisa da tutte le istanze della stessa classe.

  • Una proprietà o un metodo statico può solo accedere o modificare variabili statiche.

Un metodo o una variabile può essere pubblico o privato. Una proprietà è sempre pubblica.

I simboli privati ​​possono essere usati solo dalla classe stessa al proprio interno. I simboli pubblici possono essere utilizzati ovunque, purché si abbia un riferimento che punta all'oggetto.

1.3. Riferimenti

Non ci sono garbage collector in Gambas. Quindi ogni oggetto ha un contatore di riferimento che viene incrementato ogni volta che l'oggetto viene referenziato da qualsiasi variabile, array, collezione o altro oggetto e decrementato quando viene rilasciato.

Questo contatore di riferimento è zero alla creazione dell'oggetto e quando diventa nuovamente zero dopo una release di riferimento, l'oggetto viene liberato.

Se un oggetto ha creato altri oggetti al suo interno che generano eventi (ad esempio timer, socket, ecc.), i riferimenti a questi altri oggetti devono essere esplicitamente liberati prima che il riferimento all'oggetto stesso possa essere liberato. Questo perché non appena un oggetto A che genera eventi viene creato all'interno di un altro oggetto B, l'oggetto A fa riferimento internamente all'oggetto B come suo osservatore di eventi. Quindi B non può essere liberato prima che l'oggetto A sia liberato.

1.4. Oggetti non validi

Un oggetto può diventare invalid, ad esempio, perché collegato a un oggetto interno non gestito da Gambas che è stato distrutto.

Cercando di utilizzare un oggetto non valido si genera un errore.

1.5. Metodi speciali

I metodi speciali sono metodi dichiarati nelle classi, il cui nome inizia con un carattere di sottolineatura e che vengono chiamati dall'interprete nelle seguenti situazioni:
  • Quando viene creato un oggetto.

  • Quando un oggetto viene liberato.

  • Quando viene caricata la classe dell'oggetto.

  • Quando la classe dell'oggetto viene scaricata.

  • Quando si utilizza un oggetto come se fosse un'array.

  • Quando si enumera l'oggetto.

  • Quando si utilizza un oggetto come se fosse una funzione.

  • Quando un oggetto è collegato o rimosso dal suo genitore.

  • Quando si tenta di utilizzare un metodo o una proprietà di un oggetto sconosciuto.

Per ulteriori informazioni vedi Metodi speciali e Special Methods.

2. Eventi e osservatori

2.1. Eventi

Gli eventi sono segnali inviati da un oggetto quando qualcosa accade in esso.

Se un oggetto genera eventi, manterrà un riferimento sul suo osservatore predefinito o oggetto genitore.

Questo osservatore predefinito è un altro oggetto che implementa gestori di eventi. Un gestore di evento è solo un metodo pubblico che viene chiamato ogni volta che l'evento viene generato.

Di default, l'osservatore è l'oggetto corrente in cui viene dichiarato l'oggetto appena istanziato.

Per sollevare gli eventi, un oggetto deve avere un nome di evento. Questo nome di evento viene assegnato all'istanziazione dell'oggetto, quando si utilizza l'istruzione NEW e la parola chiave AS ed è il prefisso di tutti i metodi del gestore degli eventi.

Esempio

Questo crea un controllo Button che solleverà degli eventi.
Dim hButton As Button

hButton = New Button(Me) As "ButtonEventName"

Public Sub ButtonEventName_Click()

  Print "Questo è il gestore di eventi 'Click' per il pulsante precedente."

End

Se non viene specificato alcun nome evento, l'oggetto non genererà eventi.

2.2. Oggetto genitore predefinito (o osservatore predefinito)

Anche se non lo si definisce specificando il nome di evento con la sintassi As "xxx", alcuni oggetti possono avere un oggetto genitore predefinito.

Al momento, gli unici oggetti con un oggetto padre predefinito sono i forms, che si usano come oggetti padre predefiniti. Questo è stato fatto per simulare il comportamento di Visual Basic™ e aiuta i vecchi sviluppatori di VB.

Se si crea un form e si specifica il nome dell'evento con la sintassi As "xxx", tale comportamento predefinito verrà sovrascritto.

2.3. Blocco degli oggetti

Un oggetto può essere bloccato in modo che smetta di generare eventi e possa essere sbloccato in modo che li rilanci di nuovo. Vedere i metodi Object.Lock e Object.Unlock.

Alcuni eventi possono essere annullati dal gestore eventi, usando l'istruzione STOP EVENT. L'effetto di questa cancellazione dipende dall'evento.

Un oggetto viene automaticamente bloccato durante l'esecuzione del suo costruttore: esso non può inviare né ricevere eventi.

2.4. Osservatori

Observers sono oggetti che ti permettono di intercettare eventi generati da altri oggetti. Li "osservano".

Puoi intercettare gli eventi poco prima che siano stati sollevati o subito dopo.

Per ogni evento intercettato, l'osservatore genererà un evento con lo stesso nome e gli stessi argomenti. Questi eventi vengono generati in aggiunta all'evento originale gestito dall'oggetto padre.

Se si utilizza STOP EVENT all'interno di un osservatore di eventi, l'evento originale viene annullato.

Esempio

Private $hButton As Button
Private $hObserver As Observer

Public Sub Form_Open()

  $hButton = New Button(Me) As "Button"
  $hButton.Text = "&Click"
  $hButton.Height = 28
  $hButton.Width = 80
  $hObserver = New Observer($hButton) As "Observer"

End

Public Sub Observer_Click()

  Debug " Il pulsante è stato cliccato. Ho annullato l'evento!"
  Stop Event

End
 
Public Sub Button_Click()

  Debug "Se mi vedi questo è un bug!"

End

3. Ereditarietà

L'ereditarietà è il modo in cui una classe diventa una versione specializzata di un'altra classe.

3.1. Cosa viene ereditato?

La classe eredita dal suo genitore ogni metodo, proprietà, costante ed evento.

È necessario utilizzare la parola chiave ME per accedere agli elementi ereditati dal codice di implementazione della classe.

3.2. Quale classe può essere una classe genitore?

Puoi ereditare qualsiasi classe, anche quella nativa!

Ad esempio, puoi creare una classe MyListBox personalizzata che eredita ListBox ma consente di associare un tag a ciascuna voce dell'elenco.

Nota che non è possibile utilizzare INHERITS in un file di classe del modulo, poiché i moduli già ereditano la classe Form.

La profondità dell'albero dell'ereditarietà non può essere maggiore di 16. Si tratta di una costante codificata all'interno dell'interprete di Gambas.

3.3. Dispacciamento virtuale

Quando un metodo viene chiamato, o si accede a una proprietà tramite un riferimento ad un'oggetto, Gambas permette di usare il dispacciamento virtuale. Questo significa che vengono usati i dati direttamente della classe è non quelli della variabile che si riferisce all'oggetto, (come accadeva in Gambas 1.0).

3.4. Ereditarietà e costruttore

Contrariamente a tutti i linguaggi a oggetti conosciuti, ogni classe nella gerarchia dell'ereditarietà, utilizza i parametri passati al costruttore.

Supponiamo di avere la seguente struttura ereditata:

MiaListBox ---eredita da--> ListBox ---eredita da---> Control.

  • Control._new() non esiste.

  • ListBox._new() prende un parametro: il controllo padre.

  • MiaListBox._new() prende un parametro: un nome (è giusto un'esempio).

Così MiaListBox= avrà due parametri.

  • Il primo sarà inviato da MiaListBox._new().

  • Il secondo, da ListBox._new().

Fai attenzione: il ListBox._new() sarà chiamato per primo, così che vi sarà la certezza che il controllo ListBox esista quando saremo in MiaListBox.new().

Quindi creerai un controllo MyListBox in questo modo:

hMyListBox = NEW MyListBox(hContainer, "Name")

Pertanto l'ordine degli argomenti sarà il seguente:

  • Gli argomenti obbligatori vengono processati per primi, successivamente quelli opzionale se questi sono disponibili.

  • Gli argomenti delle classi più "anziane" sono specificati per primi.

In Gambas 2.0, l'ordine degli argomenti era invertito!

Ad esempio, se si dispone della seguente ereditarietà:

MyForm -> Form -> Window

il costruttore MyForm diventa:

Sub _new(FirstArg As String, SecondArg as Integer, Optional ThirdArg As Integer)

Nota: il costruttore Form non accetta argomenti e il costruttore Window accetta un argomento padre opzionale.

La firma del costruttore finale sarà:

New MyForm(FirstArg As String, SecondArg As Integer, Optional Parent As Control, Optional ThirdArg As Integer)

In linea generale, l'ordine degli argomenti per un albero di ereditarietà a tre livelli è:

  • Argomenti obbligatori del costruttore nonno.

  • Argomenti obbligatori del costruttore genitore.

  • Argomenti obbligatori del costruttore finale.

  • Argomenti facoltativi del costruttore nonno.

  • Argomenti facoltativi del costruttore genitore.

  • Argomenti facoltativi del costruttore finale.

3.5. Simbolo Overriding

Le regole per la sovrascrittura del simbolo sono le seguenti:

  • Un simbolo dinamico deve essere sovrascritto da un simbolo dinamico, uno statico da uno statico.

  • Un metodo deve essere sovrascritto da un metodo con esattamente la stessa firma.

  • Una proprietà di lettura/scrittura deve essere sovrascritta da una proprietà di lettura/scrittura.

  • Una proprietà di sola lettura deve essere sostituita da una proprietà di sola lettura.

  • Una costante può essere sostituita da un'altra costante.

Dal 3.12
  • Le variabili non possono essere ereditate.

Inoltre, la firma del simbolo nella classe figlio deve essere compatibile con la firma del simbolo nella classe genitore.
  • Per proprietà e costanti, significa che il tipo di dati figlio deve essere compatibile con il tipo di dati principale.

  • Per i metodi, significa che il tipo di dati e gli argomenti restituiti dal figlio devono essere compatibili con il tipo di dati e argomenti di ritorno dal padre.

Un tipo di dati figlio è compatibile con il tipo di dati genitore quando:
  • Sono esattamente uguali.

  • Il tipo di dati genitore è Object e il tipo di dati figlio è una qualsiasi classe.

  • Il tipo di dati genitore è una classe e il tipo di dati figlio è un'altra classe che eredita la classe genitore.

4. Componenti

I componenti di Gambas sono librerie condivise esterne scritte in C, C ++ o in Gambas che aggiungono nuove funzioni e / o classi all'interprete di Gambas.

Classes sono raggruppati in base al componente da cui provengono.

4.1. Componente interno predefinito

L'interprete include un componente interno denominato gb che definisce tutte le classi standard della lingua. Questo componente è sempre caricato di default e può essere considerato come parte della lingua.

4.2. Tabelle dei simboli

Ogni componente ha una propria tabella dei simboli di classe privata, in modo che i nomi delle classi non siano in conflitto.

4.3. Tabella globale dei simboli

Affinché i componenti possano lavorare insieme, esiste una tabella globale dei simboli, in cui sono archiviate tutte le classi esportate dai componenti e tutte le classi esportate dal progetto corrente.

Se c'è un conflitto di nomi in questa tabella globale dei simboli, l'ultima classe caricata sovrascrive la classe caricata precedente con lo stesso nome, usando l'ereditarietà. In altre parole, la classe prevalente sovrascritta, diventa un'estensione della prima. Questa ultima caratteristica può essere utilizzata per:
  • Estendere una classe già dichiarata, aggiungendo nuovi metodi o proprietà o entrambi se necessario. Per esempio, la classe gb.qt4 Application reimplementa la classe gb Application.

  • Sovrascrittura di metodi in una classe già dichiarata. Per esempio, il componente gb.form.dialog sostituisce molti dei metodi statici della classe Dialog.

4.4. Tabella dei simboli di progetto

Il vostro progetto ha il proprio simbolo privato, tipo un componente (componenti), e può esportare qualsiasi delle sue classi, tramite la tabella dei simboli globale usando la parola chiave EXPORT.

Le classi del progetto sono caricate dopo tutti i componenti. Così la vostra classe esportata, può eventualmente sovrascrivere qualsiasi classe dichiarata in un componente.

4.5. Spazi dei nomi

Dal 3.17

Gli spazi dei nomi consentono di scegliere il nome di una classe quando viene esportata.

In that public name, it is now possible to insert a colon, where the part before the colon is the "namespace". In quel nome pubblico è ora possibile inserire i due punti, dove la parte prima dei due punti è lo "spazio dei nomi".

Per l'interprete Gambas, gli spazi dei nomi sono solo una convenzione. Si occupa solo del nome completo della classe esportata.

Questa caratteristica permette di creare una libreria senza preoccuparsi di possibili conflitti di nomi di classi con altre librerie.

Vedere la documentazione di EXPORT per maggiori dettagli.

Vedi anche