Differenze tra le versioni di "Gli Oggetti e le Classi"

Da Gambas-it.org - Wikipedia.
 
(107 versioni intermedie di uno stesso utente non sono mostrate)
Riga 1: Riga 1:
Premetto che non ho intenzione, in questo articolo, di avviare una discussione teorico/pratica sul concetto di oggetto o classe, ma solo evidenziare alcuni aspetti relativi alla programmazione di tali elementi in Gambas.
+
In Gambas, il concetto e la logica degli ''Oggetti'' è stata fortemente implementata; infatti, nel linguaggio base esistono due categorie: '''Classe''' e '''Modulo'''.
 +
<BR>Queste due categorie, nella realtà, hanno pochissime differenze, nel senso che in ogni caso sono basate sul concetto di '''[[#Note|Oggetto]]'''. '''<SUP>&#091;[[#Note|Nota 1]]&#093;</sup>'''  <SUP>&#091;[[#Note|Nota 2]]&#093;</sup>
  
In Gambas, il concetto e la logica degli oggetti è stata fortemente implementata; infatti, nel linguaggio base esistono due categorie: '''classe''' e '''modulo'''.
+
=Tipologia delle Classi=
Queste due categorie, nella realtà, hanno pochissime differenze, nel senso che in ogni caso sono basate sul concetto di oggetto. |[[#Note|1]]|
+
Possiamo distinguere le '''Classi''' sotto il profilo della loro origine in tre diversi tipi:
  
La differenza sostanziale tra queste due implementazioni, è che in definitiva, il modulo non è altro che un contenitore di funzioni (o variabili), che vengono referenziate agendo sul modulo stesso. Il concetto di base, però, è identico a quello della classe, tranne per il fatto che un modulo, a differenza di una classe, non può essere creato dinamicamente ovvero, una volta stabilita la sua funzione all'interno di un'applicazione, e definiti i suoi metodi interni, l'oggetto rimane statico all'interno del programma. |[[#Note|2]]|
+
1) le ''Classi'' "[https://gambaswiki.org/wiki/comp/gb?l=it native ]" di Gambas: sono quelle ''Classi'' che appartengono di per sé all'architettura del linguaggio Gambas (ad esempio la ''Classe'' "Object");
Il discorso è molto simile, se non completamente analogo, alle classi statiche contenute nelle librerie di base di Gambas, come ad esempio "gb".
 
  
All'interno di un progetto, si ha la possibilità di creare, sia nuove classi, che nuovi moduli; il nome dei file assumono l'estensione "'''.module'''" per i moduli, e "'''.class'''" per le classi. Discorso leggermente diverso per gli oggetti grafici (esempio le Form), che creano un'ulteriore file "'''.form'''", contenente la definizione delle caratteristiche grafiche dell'oggetto e degli elementi inclusi in esso.
+
2) le ''Classi'' che "derivano" da librerie e sistemi esterni (ad esempio la ''Classe'' "Music" del Componente gb.media è costituita implementando in essa le risorse della libreria multimediale di ''GStreamer'');
  
A differenza di una classe, un modulo (come già detto) non può essere creato (esiste, e basta!), per cui non alcun costruttore, e di conseguenza nessun distruttore (vedi '''_new()''' e '''_free()''' in [[Metodi nascosti]]), non risponde ad alcun evento (anche dal fatto che non è un oggetto grafico), e non può gestire direttamente eventi (esempio un Timer).
+
3) le ''Classi'' "specifiche" create dal programmatore nel progetto per particolari esigenze di programmazione.  
  
Esempi:
+
=Differenza fra Classe e Modulo=
----
+
La differenza sostanziale tra queste due implementazioni, è che la '''''Classe''''' può possedere e pertanto fornire "Proprietà", "Metodi", "Eventi", "Variabili" e "Costanti", mentre il '''''Modulo''''' non può possedere <SPAN Style="text-decoration:underline">propri</span> "Eventi".
 +
<BR>Inoltre, un altro fondamentale elemento di differenza rispetto alla Classe è dato dalla circostanza che il ''Modulo'' non è altro che un contenitore di Funzioni e/o di Variabili e/o di Costanti, che vengono referenziate agendo sul ''Modulo'' stesso.
 +
<BR>Ciò significa che per richiamare e fruire di una risorsa del ''Modulo'' basterà utilizzare il nome identificatore del ''Modulo'' stesso.
 +
<BR>Così, se ad esempio il ''Modulo'' è stato chiamato dal programmatore "mio_modulo.module", e possiede un "Metodo", chiamato "Metododelmodulo()", per invocare detto "Metodo" nel codice basterà scrivere:
 +
mio_modulo.Metododelmodulo()
 +
Il concetto di base, però, è identico a quello della ''Classe'', tranne per il fatto che <SPAN Style="text-decoration:underline">di un ''Modulo''</span>, a differenza di una ''Classe'', <SPAN Style="text-decoration:underline">non possono essere creati dinamicamente "Oggetti"</span> (non possono essere create "istanze" del ''Modulo''): una volta stabilita la sua funzione all'interno di un'applicazione, e definiti i suoi "Metodi" interni, il ''Modulo'' rimane "''statico'' " all'interno del programma. <SUP>&#091;[[#Note|Nota 3]]&#093;</sup>
 +
<BR>Il discorso è molto simile, se non completamente analogo, alle ''Classi'' "statiche" contenute nelle librerie di base di Gambas, come ad esempio "gb".
 +
 
 +
Diversamente, una ''Classe'', perché possa fornire concretamente le risorse ("Proprietà", "Metodi", "Eventi", "Variabili" e "Costanti") possedute, deve essere "istanziata", ossia è necessario che vengano "creati" (con la parola-chiave "NEW") dei singoli Oggetti della ''Classe''.
 +
Dim oggetto As NEW CLASSE
 +
Un '''[[#Note|Oggetto]]''' '''<SUP>&#091;[[#Note|Nota 1]]&#093;</sup>''' in Gambas è una struttura di dati che fornisce concretamente Proprietà, Metodi ed Eventi, previsti in astratto dalla "Classe" alla quale esso appartiene.
 +
<BR>Di una ''Classe'' è possibile creare anche più "Oggetti" individuali.
 +
<BR>Pertanto, a differenza del ''Modulo'' la ''Classe'' - purché non sia di tipo ''[[CREATE_PRIVATE...CREATE_STATIC|Statico]]'' - non può essere utilizzata in modo diretto nel codice, ma deve essere utilizzata "mediante" suoi Oggetti: deve essere "istanziata".
  
  'Esempio 1: creazione di una classe dinamica
+
All'interno di un progetto, si ha la possibilità di creare, sia nuove ''Classi'', che nuovi ''Moduli''; il nome dei file assumono l'estensione "'''.module'''" per i ''Moduli'', e "'''.class'''" per le ''Classi''. Discorso leggermente diverso per gli oggetti grafici (esempio le Form), che creano un'ulteriore file "'''.form'''", contenente la definizione delle caratteristiche grafiche dell'oggetto e degli elementi inclusi in esso.
  DIM hWin AS '''NEW Window()'''
 
  
  'Esempio 2: referenziazione di una classe dinamica
+
A differenza di una ''Classe'', un ''Modulo'' (come già detto) non può essere creato (esiste, e basta!), per cui non ha alcun ''Costruttore'', e di conseguenza nessun ''Distruttore'' (vedi '''_new()''' e '''_free()''' in [[Metodi nascosti]]) e non possiede propri ''Eventi'', né può sollevarne attraverso l'istruzione "''[[Gli_eventi#Creare_un_Evento_proprio_di_un_Oggetto_creato_dall.27utente_-_L.27istruzione_Event|Event]]'' ". <SUP>&#091;[[#Note|Nota 4]]&#093;</sup>
  '''DIM hWin2 AS Window'''
 
  '''hWin2 = hWin'''
 
  
  'Esempio 3: utilizzo di una funzione modulo
 
  DIM value AS Float = '''ModUtil.CalcoloPerc(10)'''
 
  
 +
Ricapitolando possiamo dire che:
 +
* La <FONT Color=red><B>CLASSE</b></font>:
 +
<BR> - per essere utilizzata <SPAN Style="text-decoration:underline">deve</span> essere "istanziata". Le risorse di una ''Classe'' sono dunque utilizzabili esclusivamente attraverso la creazione <SPAN Style="text-decoration:underline">uno o più</span> ''Istanze/Oggetti'', rappresentati da variabili identficatrici del tipo della ''Classe'' specifica.
 +
<BR> -  possiede '''propri''' ''Eventi'', e può sollevarne mediante le combinate istruzioni "Event" e "Raise".
 +
 +
* Il <FONT Color=#006400><B>MODULO</b></font>:
 +
<BR> - può essere utilizzato esclusivamente in modo diretto attraverso il suo nome identificatore. <SPAN Style="text-decoration:underline">Non</span> è possibile creare Istanze/Oggetti di un ''Modulo''.
 +
<BR> - <U>non</u> possiede propri ''Eventi'' (sebbene possa comunque contenere routine relative ad Eventi di altre Classi), <U>né</u> può sollevarne mediante le combinate istruzioni "Event" e "Raise".
 +
La ''Classe'' '''Statica''' ha un comportamento identico al ''Modulo'' ed è a questo in tutto paragonabile.
 
----
 
----
Negli esempi sono mostrati alcuni modi di utilizzo, sia riguardo le classi, sia riguardo un modulo:
 
  
 +
 +
===Esempi===
 +
Nei seguenti esempi sono mostrati alcuni modi di utilizzo, sia riguardo alle ''Classi'', sia riguardo ai Moduli:
 +
<FONT Color=gray>' ''Esempio 1: creazione di una classe dinamica:''</font>
 +
  DIM <FONT Color=red>hWin</font> AS '''NEW Window()'''
 +
 +
<FONT Color=gray>' ''Esempio 2: referenziazione di una classe dinamica:''</font>
 +
  DIM <FONT Color=blue>hWin2</font> AS '''Window'''
 +
 +
  '''<FONT Color=blue>hWin2</font> = <FONT Color=red>hWin</font>'''
 +
 +
<FONT Color=gray>' ''Esempio 3: utilizzo di una funzione Modulo:''</font>
 +
  DIM value AS Float = '''ModUtil.CalcoloPerc(10)'''
 
a) Nell'esempio 1 viene creato un nuovo oggetto di tipo Window, e referenziato dalla variabile hWin.
 
a) Nell'esempio 1 viene creato un nuovo oggetto di tipo Window, e referenziato dalla variabile hWin.
  
b) Nell'esempio 2 viene definita una variabile di tipo Window, che viene poi associata all'oggetto precedente hWin; in questo caso non viene creato un nuovo oggetto, ma solo un riferimento a quello già esistente. In questo caso, l'eliminazione della variabile hWin2 non distruggerà l'oggetto hWin, ma toglierà solo il suo riferimento; in ogni caso la variabile precedente hWin, ovvero il vero riferimento all'oggetto, manterrà sempre l'oggetto in memoria. L'eliminazione dell'oggetto dovrà essere eseguita agendo sul proprio metodo ".Delete()" (se presente), o eliminando la stessa variabile hWin. E' da notare che, se viene cancellata la variabile originale hWin, e viene mantenuta hWin2, l'oggetto resta comunque in memoria, dato che esiste comunque un suo riferimento valido. Questo giochetto può essere molto utile in alcuni casi, ma è necessario fare molta attenzione a non lasciare appesi riferimenti inutili.
+
b) Nell'esempio 2 viene definita una variabile (''hWin2'') di tipo ''Window'', che viene poi associata all'Oggetto precedente ''hWin''; in questo caso non viene creato un nuovo Oggetto, ma solo un riferimento a quello già esistente. <BR>In questo caso, l'eliminazione della variabile ''hWin2'' non distruggerà l'oggetto ''hWin'', ma toglierà solo il suo riferimento. In ogni caso la variabile precedente ''hWin'', ovvero il vero riferimento all'oggetto, manterrà sempre l'oggetto in memoria. L'eliminazione dell'oggetto dovrà essere eseguita agendo sul proprio Metodo ".Delete()" (se presente), o eliminando la stessa variabile ''hWin''.
 +
<BR>E' da notare che, se viene cancellata la variabile originale ''hWin'', e viene mantenuta ''hWin2'', l'Oggetto resta comunque in memoria, dato che esiste comunque un suo riferimento valido. Questo giochetto può essere molto utile in alcuni casi, ma è necessario fare molta attenzione a non lasciare appesi riferimenti inutili.
  
c) Nell'esempio 3 viene utilizzata una funzione interna al modulo ModUtil: CalcoloPerc(). A parte la sua funzione specifica (è solo un esempio), il concetto è visibilmente diverso dall'utilizzo di una classe. L'uso della funzione CalcoloPerc() deve avvenire passando per il riferimento al modulo ModUtil, ma l'utilizzo è immediato, come anche il valore di ritorno.
+
c) Nell'esempio 3 viene utilizzata una funzione interna al Modulo ModUtil: CalcoloPerc(). A parte la sua funzione specifica (è solo un esempio), il concetto è visibilmente diverso dall'utilizzo di una classe. L'uso della funzione CalcoloPerc() deve avvenire passando per il riferimento al Modulo ModUtil, ma l'utilizzo è immediato, come anche il valore di ritorno.
  
Come per classi, i moduli possono contenere variabili interne, statiche ('''STATIC'''), private ('''PRIVATE''') e/o pubbliche ('''PUBLIC'''), e anche costanti ('''CONST'''). Dipedentemente dalla loro dichiarazione, l'uso è identico a quello di una proprietà di classe, tranne per il fatto che la proprietà (o variabile) non viene creata, ma esiste nello stesso ambito del modulo.
+
====Variabili interne al Modulo====
 +
Come per ''Classi'', i ''Moduli'' possono contenere variabili interne, statiche ('''STATIC'''), private ('''PRIVATE''') e/o pubbliche ('''PUBLIC'''), e anche costanti ('''CONST'''). Dipedentemente dalla loro dichiarazione, l'uso è identico a quello di una proprietà di classe, tranne per il fatto che la proprietà (o variabile) non viene creata, ma esiste nello stesso ambito del modulo.
 
----
 
----
  
Riga 61: Riga 91:
  
 
----
 
----
In quest'altro esempio viene mostrato il codice di una classe Window.
+
In quest'altro esempio viene mostrato il codice di una Classe Window.
  
 
Come si può notare, la struttura dei due file è molto simile (se non addirittura uguale); Gambas da parte sua, inserisce automaticamente un marcatore ad inizio file, ad evidenziare il tipo di file che si sta trattando. Ricordo che la modifica di questa nota non è permessa, e in ogni caso Gambas la reinserisce automaticamente.
 
Come si può notare, la struttura dei due file è molto simile (se non addirittura uguale); Gambas da parte sua, inserisce automaticamente un marcatore ad inizio file, ad evidenziare il tipo di file che si sta trattando. Ricordo che la modifica di questa nota non è permessa, e in ogni caso Gambas la reinserisce automaticamente.
  
 +
===Copia e clone di un Oggetto===
 +
Per gli Oggetti, una copia equivale a copiare l'indirizzo in memoria dell'oggetto, e quindi il suo riferimento. Ogni modifica apportata su qualsiasi variabile che contenga il solo indirizzo, modifica di conseguenza l'Oggetto.
 +
 +
Per avere invece un clone, ossia duplicato dell'Oggetto, è necessario usare il Metodo - laddove la Classe lo disponga - ".Copy()", che crea un clone dell'Oggetto, ma in ''altra'' zona di memoria.
 +
<BR>Non tutti gli oggetti base hanno un Metodo ".Copy()"; in tal caso caso è necessario implementarlo, creando un nuovo Oggetto e copiando le proprietà dell'originale sul nuovo.
  
''Parliamo ora degli oggetti (o classi)...''
 
  
Come già descritto, le classi differiscono dai moduli, principalmente per il fatto che possono e devono essere creati e istanziati.
+
==Particolari parole-chiave della Classe: ME - SUPER - INHERITS==
 +
Come già descritto, le ''Classi'' differiscono dai moduli, principalmente per il fatto che possono e devono essere creati e istanziati.
 
Oltre a questo, hanno alcune particolarità, che ne semplificano l'uso, e oltre tutto devono obbligatoriamente possedere, per poter gestire un oggetto in maniera umana.
 
Oltre a questo, hanno alcune particolarità, che ne semplificano l'uso, e oltre tutto devono obbligatoriamente possedere, per poter gestire un oggetto in maniera umana.
 
A parte i propri metodi e le loro proprietà, che dipendono dal tipo di oggetto e dal tipo di funzione che deve svolgere, esistono delle parole chiave, con lo scopo di fornire elementi utili al loro utilizzo.
 
A parte i propri metodi e le loro proprietà, che dipendono dal tipo di oggetto e dal tipo di funzione che deve svolgere, esistono delle parole chiave, con lo scopo di fornire elementi utili al loro utilizzo.
Riga 74: Riga 109:
  
  
'''ME - Riferimento a se stesso'''
+
===ME - Riferimento a se stesso===
  
La ''parola chiave'' |[[#Note|3]]| '''ME''' è messa a disposizione per poter puntare all'oggetto, all'interno di se stesso; cosa che altrimenti non sarebbe fattibile.
+
La ''parola chiave'' <SUP>&#091;[[#Note|Nota 5]]&#093;</sup> '''ME''' è messa a disposizione per poter puntare all'oggetto, all'interno di se stesso; cosa che altrimenti non sarebbe fattibile.
 
Come per i moduli, che si referenziano esternamente, dichiarando il nome del modulo stesso, per le classi, all'interno dei loro metodi, si può avere un riferimento allo stesso oggetto con '''ME'''.
 
Come per i moduli, che si referenziano esternamente, dichiarando il nome del modulo stesso, per le classi, all'interno dei loro metodi, si può avere un riferimento allo stesso oggetto con '''ME'''.
 
----
 
----
Riga 143: Riga 178:
  
  
'''SUPER - Riferimento alla classe superiore'''
+
===SUPER - Riferimento alla classe superiore===
  
Un oggetto (o classe) può essere derivata da un oggetto (o classe) superiore; in questo caso la nuova classe assume tutte le carattersitiche PUBLIC della classe padre, e la possibilità di espanderne le proprietà e/o specializzarne la funzione. Un esempio è la classe CheckBox, che deriva dalla classe Control.
+
Un oggetto (o classe) può essere derivata da un oggetto (o classe) superiore; in questo caso la nuova classe assume tutte le caratteristiche PUBLIC della classe padre, e la possibilità di espanderne le proprietà e/o specializzarne la funzione. Un esempio è la classe ''CheckBox'', che deriva dalla classe ''Control''.
 
----
 
----
 
   
 
   
Riga 167: Riga 202:
  
 
----
 
----
Nell'esempio è mostrato il codice della classe MyWindow, che deriva dalla classe base Window di Gambas. La nuova classe assume tutte le caratteristiche PUBLIC della classe Window, comprese le proprietà, i metodi e i gestori di evento. A questo punto non è necessario riscriverne le proprietà, dato che sono già impostate a livello di classe padre; al più possiamo aggiungerne di altre, specializzando la funzione di questo nuovo oggetto.
+
Nell'esempio è mostrato il codice della classe MyWindow, che deriva dalla classe base ''Window'' di Gambas. La nuova classe assume tutte le caratteristiche PUBLIC della classe ''Window'', comprese le proprietà, i metodi e i gestori di evento. A questo punto non è necessario riscriverne le proprietà, dato che sono già impostate a livello di classe padre; al più possiamo aggiungerne di altre, specializzando la funzione di questo nuovo oggetto.
 
In realtà è anche possibile sovrascrivere una specifica funzionalità, rispetto alla classe padre; in questo caso è sufficiente ricreare il metodo, scrivendoci dentro il codice desiderato.
 
In realtà è anche possibile sovrascrivere una specifica funzionalità, rispetto alla classe padre; in questo caso è sufficiente ricreare il metodo, scrivendoci dentro il codice desiderato.
 
Ma come facciamo a interagire con la classe padre? Semplice, in questo caso ci viene in aiuto un'altra parola chiave: '''SUPER'''.
 
Ma come facciamo a interagire con la classe padre? Semplice, in questo caso ci viene in aiuto un'altra parola chiave: '''SUPER'''.
Riga 186: Riga 221:
  
 
----
 
----
Nell'esempio viene utilizzato il metodo Resize, nel quale abbiamo scritto codice adatto ai nostri scopi, e poi eseguiamo anche la stessa funzione nella classe padre, che potrebbe essere necessaria, in questo caso, a risolvere e attuare eventuali aggiustamente alla Window.
+
Nell'esempio viene utilizzato il metodo ''.Resize'', nel quale abbiamo scritto codice adatto ai nostri scopi, e poi eseguiamo anche la stessa funzione nella classe padre, che potrebbe essere necessaria, in questo caso, a risolvere e attuare eventuali aggiustamenti alla Window.
  
Nello stesso esempio è presente anche un'altra parola chiave: '''INHERITS'''; ma questo è descritto in modo esplicativo in [[Inherits]].
+
===INHERITS===
 +
Nello stesso esempio è presente anche un'altra parola chiave: '''[[INHERITS]]'''.
  
 +
==Metodi nascosti==
 
Per ogni oggetto, sia che venga creato da noi, sia che faccia parte delle librerie standard di Gambas, esistono dei metodi, nascosti, che possono essere utilizzati per condizionare la creazione, o meno, dell'oggetto stesso. Questi metodi sono descritti in [[Metodi nascosti]].
 
Per ogni oggetto, sia che venga creato da noi, sia che faccia parte delle librerie standard di Gambas, esistono dei metodi, nascosti, che possono essere utilizzati per condizionare la creazione, o meno, dell'oggetto stesso. Questi metodi sono descritti in [[Metodi nascosti]].
  
  
 +
==Classi ''virtuali''==
 +
Tobias Boege, membro della Mailing list ufficiale di Gambas, descrive quanto segue:
 +
<BR>«''Esistono due tipi di classi virtuali: classi "native" e classi "virtuali" di Gambas.''
 +
<BR>''E' possibile distinguerle approssimativamente dal Componente da cui provengono o dal primo carattere nel loro nome;''
 +
<BR>* ''un punto iniziale significa nativo (ad es. .Menu.Children dal Componente nativo gb.qt4 o .Watch.Events da gb.inotify);''
 +
<BR>* ''un trattino basso che significa che è scritto in Gambas (ad es. _MapTile in gb.map).
 +
<BR>''Questa denominazione non è un requisito ma una convenzione.''
 +
 +
''Una classe virtuale ha lo scopo di fornire un'interfaccia alternativa a una parte di un oggetto. Nei componenti nativi, una proprietà virtuale viene spesso implementata restituendo lo stesso oggetto esatto ma dicendo all'interprete di "eseguirne il cast" in un'altra classe, in modo da disporre di un set di Metodi più specializzato. Molti componenti si basano sul presupposto che possono semplicemente inserire alcuni dati in un campo nella struttura dati sottostante dell'oggetto e restituire se stessi per implementare una proprietà virtuale e che i dati non verranno toccati fino a quando l'oggetto virtuale non viene eseguito.''
 +
<BR>''L'accessorio di proprietà di solito imposta una sorta di flag o registra alcuni parametri di accesso come lo slot delle impostazioni in _Settings_Keys._get () in modo che i metodi più specializzati sappiano dove si vuole che funzionino.''
 +
<BR>''Si può vedere che con il nome delle classi virtuali native: .Menu.Children è una classe virtuale per la gestione della proprietà .Children di un oggetto Menu e .Watch.Events fa lo stesso per .Events di un Watch.''
 +
<BR>''In realtà, le classi virtuali di Gambas (quelle che non sono native) sono solo normali classi. La "fusione di parte di un oggetto in una classe diversa" è una funzionalità strettamente nativa. Probabilmente non dovrebbero nemmeno essere chiamati "virtuali" ma sono spesso usati per lo stesso scopo. Il carattere di sottolineatura principale viene generalmente utilizzato per nascondere le classi, ad es. al popup di completamento automatico IDE. Si potrebbe teoricamente archiviare questi oggetti in un array, ma neanche questo è sicuro, a seconda di quali ipotesi la Classe faccia durante la sua vita.''
 +
<BR>''Ora è possibile vedere il problema: gli oggetti virtuali in realtà non esistono. Sono solo una vista volatile su una parte specifica di un oggetto. Quindi non è possibile porli in un array. Le Classi virtuali possono essere dichiarate nei Componenti nativi, ma non sono creabili e hanno sempre la dimensione zero.''
 +
 +
''Una Proprietà o un Metodo virtuale consente di eseguire del codice nell'implementazione della proprietà o del metodo, che di solito registra solo alcuni dati nella memoria dell'oggetto e quindi restituisce l'oggetto stesso tramite RETURN_SELF (GB_PROPERTY_SELF è una scorciatoia per restituire se stessi e non fare nulla altro), ma l'interprete considera il valore restituito (sempre lo stesso oggetto) non come del suo vero tipo ma del tipo restituito indicato nella dichiarazione di proprietà.''
 +
<BR>''Improvvisamente, lo stesso oggetto assume un'interfaccia completamente diversa, nuovi metodi, nuove proprietà. Ma è la stessa regione in memoria, quindi le implementazioni di queste nuove proprietà e metodi possono accedere all'oggetto originale. Viene normalmente utilizzato per fornire una vista specializzata sull'oggetto.''
 +
<BR>''Tutto ciò implica, tra l'altro, che non è possibile archiviare oggetti virtuali in memoria, poiché sono solo viste temporanee su un altro oggetto. E l'uso di oggetti virtuali è intrinsecamente pericoloso per i ''thread'' poiché, a seconda della rispettiva implementazione, nel processo potrebbe esserci un solo oggetto virtuale per un determinato oggetto reale in qualsiasi momento.''
 +
 +
''Non è possibile implementare classi virtuali in Gambas. Lo si può fare solo usando l'API C/C ++ nativa dell'interprete, che ha la magia di cambiare un BLOB di descrizione dell'interfaccia con un altro. Tutto ciò che viene scritto in ​​Gambas è una vera classe in cui non si può staccare la memoria dall'interfaccia.
 +
<BR>''Le classi virtuali sono in realtà solo un trucco nell'interprete per "eseguire il cast parametrico" di un oggetto in un'altra classe per non inquinare, per esempio, l'interfaccia diretta della classe Array con metodi e proprietà correlati ai suoi limiti, poiché quelli possono essere nascosti in un vista virtuale sull'array.''
 +
<BR>''Le classi virtuali consentono di fare ciò:''
 +
<BR>''1) in modo non dispendioso (perché tutto ciò che deve essere fatto è sostituire il puntatore al tipo di un oggetto);''
 +
<BR>''2) senza dover creare nuovi oggetti e quindi creare interfacce della classe originale (semi-) pubblico in modo che questi nuovi oggetti possano accedervi.''
 +
 +
''Il solito modo di emulare questo in Gambas è:''
 +
<BR>''- creare Classi reali per le viste virtuali, come _Array_Bounds con un Costruttore di _new (RealObject As Array);''
 +
<BR>''- Array.Bounds restituisce una nuova istanza di questo _Array_Bounds e passa il riferimento "Me" al Costruttore;''
 +
<BR>''- la classe Array deve rendere pubblici alcuni interni in modo che _Array_Bounds possa accedervi, essendo ora un oggetto diverso.''
 +
 +
''Solitamente questi sono preceduti da un trattino basso in modo che l'IDE li nasconda dalle opinioni delle persone normali.'' »
 +
 +
 +
=Un indice delle Classi di Gambas=
 +
Nella seguente pagina web è possibile vedere un elenco della Classi di Gambas:
 +
https://www.gambas.one/classes/
 +
Ogni Classe è collegata alla rispettiva pagina della Wiki ufficiale di Gambas.
  
  
 
----
 
----
==Note==
+
=Note=
 
[1] Bisogna ricordare che un ''Oggetto'' non è altro che una ''Classe istanziata''.
 
[1] Bisogna ricordare che un ''Oggetto'' non è altro che una ''Classe istanziata''.
  miaClasse = New mclass
+
  oggetto = New Classe
''miaClasse'' è appunto un ''Oggetto''.
+
laddove la variabile ''oggetto'' è appunto un ''Oggetto''.
 +
<BR>Con parola-chiave ''New''  viene creato un ''Oggetto'', appartenente ad una specifica ''Classe'', allocando automaticamente la necessaria quantità di memoria richiesta per esso e che così rappresenta la struttura interna dell'Oggetto medesimo.
 +
<BR>Infatti, gli "Oggetti" in Gambas sono costituiti da Strutture e Sub-Strutture, scritte in C, che ovviamente occupano memoria.
 +
 
 +
E' il caso di sottolineare che è un errore l'uso - come <SPAN Style="text-decoration:underline">''argomento''</span> di una funzione - di una variabile di un Oggetto che <SPAN Style="text-decoration:underline">non sia stato creato</span> con la parola ''New'' o che non derivi dal ritorno di altra funzione oppure che non sia associata a un Oggetto della medesima Classe.
 +
 
 +
La variabile che funge da ''Puntatore'' a un ''Oggetto'' sovente è definita "''Handle'' " (maniglia), che rappresenta "''una variabile associata a un oggetto complesso, che lo identifica''". La maniglia è la "protuberanza", con la quale si interagisce con l'<I>Oggetto</i>. In Gambas, qualsiasi ''Oggetto'' (Form, o altro) è dunque in sostanza un "''Handle'' ".
 +
Questo "handle", questa variabile che rappresenta l'Oggetto di una ''Classe'', dunque individua, indica e in certo senso fornisce al programmatore la prima cella di memoria della Struttura principale che costituisce l'Oggetto medesimo.
 +
<BR>Questa prima cella di memoria, ove inizia la memoria riservata dal sistema per l'esistenza e la funzionalità dell'Oggetto di una ''Classe'', possiede ovviamente un Indirizzo.
 +
<BR>La variabile di un Oggetto, puntando all'area di memoria riservata all'Oggetto, punta dunque a quell'Indirizzo di memoria, si riferisce esplicitamente a quella cella di memoria; anzi esso contiene come valore proprio l'indirizzo di memoria di quella cella.
 +
 
 +
In Gambas gli ''Oggetti'' sono entità individuali concrete di un ''insieme'' più ampio, di un Universale che li trascende, chiamato ''Classe'', e che rappresenta per essi un Modello, una Categoria ''assoluta'' delle loro caratteristiche (''Proprietà'', ''Metodi'', ''Eventi'', ''Variabili'' e ''Costanti'') possedute che li distinguono dagli ''Oggetti'' appartenenti ad altre ''Classi''.
 +
<BR>Pertanto gli ''Oggetti'', singolarità di una ''Classe'', per esistere devono, come ogni entità concreta immanente, essere <SPAN Style="text-decoration:underline">creati</span>.
 +
 
 +
Una ''Classe'' concettualmente è ciò che è comune a più realtà individuali e concrete: gli ''Oggetti'', accomunati tutti dalla circostanza di possedere e di fornire le risorse della ''Classe'', alla quale essi appartengono. La ''Classe'', dunque, è un "insieme" che raggruppa molti elementi individuali - gli ''Oggetti'' - che posseggono caratteristiche comuni.
 +
<BR>Tali caratteristiche in Gambas possono essere rappresentate dalle seguenti risorse:
 +
* '''Proprietà''' (capacità dell'Oggetto di assumere una qualità);
 +
* '''Metodi''' (capacità dell'Oggetto di compiere un'operazione);
 +
* '''Eventi''' (capacità dell'Oggetto di far accadere qualcosa in caso di una sua sollecitazione);
 +
* '''Variabili''';
 +
* '''Costanti'''.
 +
La "Classe", dunque, è un sistema organico di risorse tra loro coerenti per la realizzazione di una o più finalità.
 +
<BR>La ''Classe'', come già detto, è il ''modello'' contenente specifiche caratteristiche (Metodi, Proprietà, Eventi, Variabili e Costanti), al quale fanno riferimento singoli elementi: gli ''Oggetti''. In tal senso gli ''Oggetti'' appartengono ad una ''Classe'', ossia sono la rappresentazione concreta delle caratteristiche e delle potenzialità di una ''Classe''. Essi sono gli elementi capaci di fornire concretamente al programmatore ed all'utente le funzionalità della ''Classe'', alla quale essi appartengono. Infatti, la ''Classe'' in sé non può essere utilizzata ''sic et simpliciter'' all'interno di un codice (ad eccezione delle Classi ''Statiche''), giacché essa <SPAN Style="text-decortion:undeline">solo in astratto</span> possiede alcune specifiche funzionalità. Tali capacità possono essere ''concretamente'' utilizzate solo attraverso elementi individuali, gli ''Oggetti'', che alla ''Classe'' (astratta) fanno riferimento.
 +
<BR>La ''Classe'' specifica, dunque, le sue caratteristiche e funzionalità, le quali potranno essere utilizzate e gestite mediante gli ''Oggetti''. In particolare la ''Proprietà'' di un ''Oggetto'' è un'informazione definibile come ''attributo'' dell'<I>Oggetto</i> medesimo.
 +
<BR>Tali funzionalità e caratteristiche (Metodi, Proprietà, Eventi, Variabili e Costanti) di una ''Classe'' sono tra loro coerenti ed organici alle specificità ed alle potenzialità della ''Classe'', in modo tale che la ''Classe'' possa svolgere i compiti, per i quali fu creata.
 +
<BR>La ''Classe'' è l'elemento ''astratto'', nella quale sono definite determinate funzionalità, compiti e caratteristiche (Metodi, Proprietà, Eventi, Variabili e Costanti); mentre l'<I>Oggetto</i> è l'elemento ''concreto'', virtualmente materiale, utilizzabile nel codice, e che rende possibile l'uso delle potenzialità della ''Classe'', alla quale esso appartiene. In sostanza la ''Classe'' è utilizzabile solo attraverso gli ''Oggetti'' che ad essa si riferiscono.
 +
<BR>La ''dinamicità'' della ''Classe'' è dovuta anche a questa sua capacità e necessità di esteriorizzarsi, di concretizzarsi in una possibile molteplicità di elementi (gli ''Oggetti'') che ad essa si riferiscono, e che la rendono così effettivamente utilizzabile nel codice e, dunque, nel programma.
 +
<BR>Tale <SPAN Style="Text-decoration:underline">non</span> staticità di una "Classe" consente al programmatore di creare più Oggetti di essa (questa facoltà non è consentita ad esempio per le Classi statiche e per i Moduli che sono "statici" per propria natura).
 +
 
 +
Per comprendere a pieno il concetto di "''istanza''" di una ''Classe'', è opportuno comprendere l'etimo della parola, che proveniendo dal latino "''in'' + ''sto''", vuol significare "''stare in''", e quindi "''stare nel (mondo)''", "''starci''", "''esistere nella (realtà)''".
 +
Una ''Classe'' in quanto ''modello'' non esiste nel/sul mondo, ossia concretamente, è semplicemente un predicato astratto, un paradigma.
 +
Se la ''Classe'' si fa concreta, si ''in-stanzia'', ossia si ''in-pone'' nella realtà concreta del programma, diventa gestibile in modo effettivo, virtualmente tangibile: diventa insomma un "''Oggetto''". L'''Oggetto'' si pone, sta nel ''mondo'' del programma informatico con una sua individualità, definita e condizionata da funzionalità e caratteristiche che rimandano necessariamente alla sua ''Classe'' di appartenenza.
 +
 
 +
Per accedere all'uso delle risorse (Metodi, Proprietà, Eventi, Variabili e Costanti) di una ''Classe'' si adopererà l'operatore "'''.'''" che distingue la variabile - identificatrice dell'Oggetto costruito - dalla sua risorsa, specificandone nello stesso tempo tipo e appartenenza:
 +
nome_variabile'''.'''nome_risorsa
 +
 
 +
[2] Vedere anche le seguenti discussioni sul forum:
 +
<BR> - https://www.gambas-it.org/smf/index.php?topic=933.0
 +
<BR> - https://www.gambas-it.org/smf/index.php?topic=242
  
[2] Minisini, rispondendo nella Mailing List ufficiale di Gambas, ha così brevemente definito il ''Modulo'':
+
[3] Minisini, rispondendo nella Mailing List ufficiale di Gambas, ha così brevemente definito il ''Modulo'':
 
  "''A module is just a class whose all methods and properties are static.''
 
  "''A module is just a class whose all methods and properties are static.''
 
  ''It's a thing coming from Visual Basic.''
 
  ''It's a thing coming from Visual Basic.''
 
  ''It's like a class, except everything is static.''
 
  ''It's like a class, except everything is static.''
 
  ''It's static, that means it cannot be instantiated.''"
 
  ''It's static, that means it cannot be instantiated.''"
 +
Va ricordato che a una Classe ''statica'' o a un Modulo (che è di per sé ''statico'') si può accedere senza bisogno di creare un'<I>istanza</i> della Classe o del Modulo.
 +
 +
[4] Un ''Modulo non'' può essere istanziato, non può creare il proprio ''Osservatore'', né può sollevare direttamente un Evento mediante l'istruzione "Event". Per tanto un ''Modulo'' può solo “partecipare” agli Eventi pubblici di altre Classi.
  
[3] La ''Parola Chiave''  è una parola ''riservata'' del linguaggio di programmazione, che non può essere utilizzata diversamente da ciò per cui è stata concepita.
+
[5] La ''Parola-Chiave''  è una parola ''riservata'' del linguaggio di programmazione, che ''di norma'' non può essere utilizzata diversamente da ciò per cui è stata concepita.
Per esempio nella riga:
+
<BR>Per esempio nella riga:
 
  Dim variabile As Integer
 
  Dim variabile As Integer
la parola "''Dim''" è una ''parola chiave'', mentre non lo è la parola "''variabile''".
+
la parola "''Dim''" è una ''parola-chiave'', mentre non lo è la parola "''variabile''".
 +
 
 +
In vero, però, <U>in Gambas</u> una ''parola-chiave'' può essere utilizzata come identificativa di una variabile, purché posta fra due parentesi ''graffe'':
 +
Dim {Dim} As Integer
 +
 +
{Dim} = 100000
 +
 
 +
Print {Dim}
 +
 
 +
 
 +
=Riferimenti=
 +
* '''http://gambaswiki.org/wiki/doc/object-model?l=it'''
 +
* http://gambaswiki.org/wiki/doc/object-model

Versione attuale delle 02:36, 16 ott 2024

In Gambas, il concetto e la logica degli Oggetti è stata fortemente implementata; infatti, nel linguaggio base esistono due categorie: Classe e Modulo.
Queste due categorie, nella realtà, hanno pochissime differenze, nel senso che in ogni caso sono basate sul concetto di Oggetto. [Nota 1] [Nota 2]

Tipologia delle Classi

Possiamo distinguere le Classi sotto il profilo della loro origine in tre diversi tipi:

1) le Classi "native " di Gambas: sono quelle Classi che appartengono di per sé all'architettura del linguaggio Gambas (ad esempio la Classe "Object");

2) le Classi che "derivano" da librerie e sistemi esterni (ad esempio la Classe "Music" del Componente gb.media è costituita implementando in essa le risorse della libreria multimediale di GStreamer);

3) le Classi "specifiche" create dal programmatore nel progetto per particolari esigenze di programmazione.

Differenza fra Classe e Modulo

La differenza sostanziale tra queste due implementazioni, è che la Classe può possedere e pertanto fornire "Proprietà", "Metodi", "Eventi", "Variabili" e "Costanti", mentre il Modulo non può possedere propri "Eventi".
Inoltre, un altro fondamentale elemento di differenza rispetto alla Classe è dato dalla circostanza che il Modulo non è altro che un contenitore di Funzioni e/o di Variabili e/o di Costanti, che vengono referenziate agendo sul Modulo stesso.
Ciò significa che per richiamare e fruire di una risorsa del Modulo basterà utilizzare il nome identificatore del Modulo stesso.
Così, se ad esempio il Modulo è stato chiamato dal programmatore "mio_modulo.module", e possiede un "Metodo", chiamato "Metododelmodulo()", per invocare detto "Metodo" nel codice basterà scrivere:

mio_modulo.Metododelmodulo()

Il concetto di base, però, è identico a quello della Classe, tranne per il fatto che di un Modulo, a differenza di una Classe, non possono essere creati dinamicamente "Oggetti" (non possono essere create "istanze" del Modulo): una volta stabilita la sua funzione all'interno di un'applicazione, e definiti i suoi "Metodi" interni, il Modulo rimane "statico " all'interno del programma. [Nota 3]
Il discorso è molto simile, se non completamente analogo, alle Classi "statiche" contenute nelle librerie di base di Gambas, come ad esempio "gb".

Diversamente, una Classe, perché possa fornire concretamente le risorse ("Proprietà", "Metodi", "Eventi", "Variabili" e "Costanti") possedute, deve essere "istanziata", ossia è necessario che vengano "creati" (con la parola-chiave "NEW") dei singoli Oggetti della Classe.

Dim oggetto As NEW CLASSE

Un Oggetto [Nota 1] in Gambas è una struttura di dati che fornisce concretamente Proprietà, Metodi ed Eventi, previsti in astratto dalla "Classe" alla quale esso appartiene.
Di una Classe è possibile creare anche più "Oggetti" individuali.
Pertanto, a differenza del Modulo la Classe - purché non sia di tipo Statico - non può essere utilizzata in modo diretto nel codice, ma deve essere utilizzata "mediante" suoi Oggetti: deve essere "istanziata".

All'interno di un progetto, si ha la possibilità di creare, sia nuove Classi, che nuovi Moduli; il nome dei file assumono l'estensione ".module" per i Moduli, e ".class" per le Classi. Discorso leggermente diverso per gli oggetti grafici (esempio le Form), che creano un'ulteriore file ".form", contenente la definizione delle caratteristiche grafiche dell'oggetto e degli elementi inclusi in esso.

A differenza di una Classe, un Modulo (come già detto) non può essere creato (esiste, e basta!), per cui non ha alcun Costruttore, e di conseguenza nessun Distruttore (vedi _new() e _free() in Metodi nascosti) e non possiede propri Eventi, né può sollevarne attraverso l'istruzione "Event ". [Nota 4]


Ricapitolando possiamo dire che:

* La CLASSE:

- per essere utilizzata deve essere "istanziata". Le risorse di una Classe sono dunque utilizzabili esclusivamente attraverso la creazione uno o più Istanze/Oggetti, rappresentati da variabili identficatrici del tipo della Classe specifica.
- possiede propri Eventi, e può sollevarne mediante le combinate istruzioni "Event" e "Raise". * Il MODULO:
- può essere utilizzato esclusivamente in modo diretto attraverso il suo nome identificatore. Non è possibile creare Istanze/Oggetti di un Modulo.
- non possiede propri Eventi (sebbene possa comunque contenere routine relative ad Eventi di altre Classi), può sollevarne mediante le combinate istruzioni "Event" e "Raise".

La Classe Statica ha un comportamento identico al Modulo ed è a questo in tutto paragonabile.



Esempi

Nei seguenti esempi sono mostrati alcuni modi di utilizzo, sia riguardo alle Classi, sia riguardo ai Moduli:

' Esempio 1: creazione di una classe dinamica:
 DIM hWin AS NEW Window()
' Esempio 2: referenziazione di una classe dinamica:
 DIM hWin2 AS Window

 hWin2 = hWin
' Esempio 3: utilizzo di una funzione Modulo:
 DIM value AS Float = ModUtil.CalcoloPerc(10)

a) Nell'esempio 1 viene creato un nuovo oggetto di tipo Window, e referenziato dalla variabile hWin.

b) Nell'esempio 2 viene definita una variabile (hWin2) di tipo Window, che viene poi associata all'Oggetto precedente hWin; in questo caso non viene creato un nuovo Oggetto, ma solo un riferimento a quello già esistente.
In questo caso, l'eliminazione della variabile hWin2 non distruggerà l'oggetto hWin, ma toglierà solo il suo riferimento. In ogni caso la variabile precedente hWin, ovvero il vero riferimento all'oggetto, manterrà sempre l'oggetto in memoria. L'eliminazione dell'oggetto dovrà essere eseguita agendo sul proprio Metodo ".Delete()" (se presente), o eliminando la stessa variabile hWin.
E' da notare che, se viene cancellata la variabile originale hWin, e viene mantenuta hWin2, l'Oggetto resta comunque in memoria, dato che esiste comunque un suo riferimento valido. Questo giochetto può essere molto utile in alcuni casi, ma è necessario fare molta attenzione a non lasciare appesi riferimenti inutili.

c) Nell'esempio 3 viene utilizzata una funzione interna al Modulo ModUtil: CalcoloPerc(). A parte la sua funzione specifica (è solo un esempio), il concetto è visibilmente diverso dall'utilizzo di una classe. L'uso della funzione CalcoloPerc() deve avvenire passando per il riferimento al Modulo ModUtil, ma l'utilizzo è immediato, come anche il valore di ritorno.

Variabili interne al Modulo

Come per Classi, i Moduli possono contenere variabili interne, statiche (STATIC), private (PRIVATE) e/o pubbliche (PUBLIC), e anche costanti (CONST). Dipedentemente dalla loro dichiarazione, l'uso è identico a quello di una proprietà di classe, tranne per il fatto che la proprietà (o variabile) non viene creata, ma esiste nello stesso ambito del modulo.


' Gambas module file
.
'*** Modulo ModUtil ***
.
PUBLIC FUNCTION CalcoloPerc(value AS Float) AS Float
  ...
  ...
  ...
END

Nell'esempio viene mostrato come può apparire il codice del modulo ModUtil, e il suo metodo (o funzione) interno.


' Gambas class file
.
'*** Classe MyWindow ***
.
PUBLIC SUB Form_Open()
  ...
  ...
  ...
END

In quest'altro esempio viene mostrato il codice di una Classe Window.

Come si può notare, la struttura dei due file è molto simile (se non addirittura uguale); Gambas da parte sua, inserisce automaticamente un marcatore ad inizio file, ad evidenziare il tipo di file che si sta trattando. Ricordo che la modifica di questa nota non è permessa, e in ogni caso Gambas la reinserisce automaticamente.

Copia e clone di un Oggetto

Per gli Oggetti, una copia equivale a copiare l'indirizzo in memoria dell'oggetto, e quindi il suo riferimento. Ogni modifica apportata su qualsiasi variabile che contenga il solo indirizzo, modifica di conseguenza l'Oggetto.

Per avere invece un clone, ossia duplicato dell'Oggetto, è necessario usare il Metodo - laddove la Classe lo disponga - ".Copy()", che crea un clone dell'Oggetto, ma in altra zona di memoria.
Non tutti gli oggetti base hanno un Metodo ".Copy()"; in tal caso caso è necessario implementarlo, creando un nuovo Oggetto e copiando le proprietà dell'originale sul nuovo.


Particolari parole-chiave della Classe: ME - SUPER - INHERITS

Come già descritto, le Classi differiscono dai moduli, principalmente per il fatto che possono e devono essere creati e istanziati. Oltre a questo, hanno alcune particolarità, che ne semplificano l'uso, e oltre tutto devono obbligatoriamente possedere, per poter gestire un oggetto in maniera umana. A parte i propri metodi e le loro proprietà, che dipendono dal tipo di oggetto e dal tipo di funzione che deve svolgere, esistono delle parole chiave, con lo scopo di fornire elementi utili al loro utilizzo.



ME - Riferimento a se stesso

La parola chiave [Nota 5] ME è messa a disposizione per poter puntare all'oggetto, all'interno di se stesso; cosa che altrimenti non sarebbe fattibile. Come per i moduli, che si referenziano esternamente, dichiarando il nome del modulo stesso, per le classi, all'interno dei loro metodi, si può avere un riferimento allo stesso oggetto con ME.


' Gambas class file
.
'*** Classe Form ***
.
PUBLIC SUB Form_Open()
  ...
  ME.Caption = "Nome della Form"
  ...
END

Nell'esempio viene impostato il testo che comparirà sulla testata della Form; come si può notare, il riferimento alla Form (ovverro a se stessa), viene fatto da ME. Il punto che segue indica al compilatore di Gambas, che il nome che seguirà sarà un riferimento ad una proprietà o un metodo interno alla classe (in questo caso Caption).


' Gambas class file
.
'*** Classe Form ***
.
PUBLIC SUB Form_Open()
  ...
  WITH ME
    ...
    .Caption = "Nome della Form"
    .X = 0
    .Y = 0
    ...
  END WITH
  ...
END

La sintassi di quest'altro esempio è la stessa, la differenza stà nel fatto di aver utilizzato la sintassi WITH...END WITH. Questo tipo di sintassi permette di stabilire a priori che si vogliono modificare solo elementi della classe, per cui non c'è più bisogno della parola ME, per cui i riferimenti verranno fatti iniziando i nomi delle proprietà di classe con il punto. E' sottinteso che questa logica è valida anche per i metodi, non solo per le proprietà:


' Gambas class file
.
'*** Classe Form ***
.
PUBLIC SUB Form_Open()
  ...
  WITH ME
    ...
    .Caption = "Nome della Form"
    .X = 0
    .Y = 0
    ...
    .Init()
    ...
  END WITH
  ...
END
...
...
...
PUBLIC SUB Init()
  ...
END

Come si può notare, all'interno di WITH, è presente anche la chiamata al metodo Init(), che appartiene alla stessa classe.



SUPER - Riferimento alla classe superiore

Un oggetto (o classe) può essere derivata da un oggetto (o classe) superiore; in questo caso la nuova classe assume tutte le caratteristiche PUBLIC della classe padre, e la possibilità di espanderne le proprietà e/o specializzarne la funzione. Un esempio è la classe CheckBox, che deriva dalla classe Control.


' Gambas class file
.
'*** Classe MyWindow ***
.
INHERITS Window
.
PUBLIC SUB Window_Open()
  ...
  WITH ME
    ...
    .Caption = "Nome della Window"
    .X = 0
    .Y = 0
    ...
  END WITH
  ...
END

Nell'esempio è mostrato il codice della classe MyWindow, che deriva dalla classe base Window di Gambas. La nuova classe assume tutte le caratteristiche PUBLIC della classe Window, comprese le proprietà, i metodi e i gestori di evento. A questo punto non è necessario riscriverne le proprietà, dato che sono già impostate a livello di classe padre; al più possiamo aggiungerne di altre, specializzando la funzione di questo nuovo oggetto. In realtà è anche possibile sovrascrivere una specifica funzionalità, rispetto alla classe padre; in questo caso è sufficiente ricreare il metodo, scrivendoci dentro il codice desiderato. Ma come facciamo a interagire con la classe padre? Semplice, in questo caso ci viene in aiuto un'altra parola chiave: SUPER. Ogni qualvolta entriamo in un metodo, che abbiamo sovrascritto per nostra necessità, possiamo chiamare il metodo della classe padre:


' Gambas class file
.
'*** Classe MyWindow ***
.
INHERITS Window
.
PUBLIC SUB Resize()
  ...
  SUPER.Resize()
  ...
END

Nell'esempio viene utilizzato il metodo .Resize, nel quale abbiamo scritto codice adatto ai nostri scopi, e poi eseguiamo anche la stessa funzione nella classe padre, che potrebbe essere necessaria, in questo caso, a risolvere e attuare eventuali aggiustamenti alla Window.

INHERITS

Nello stesso esempio è presente anche un'altra parola chiave: INHERITS.

Metodi nascosti

Per ogni oggetto, sia che venga creato da noi, sia che faccia parte delle librerie standard di Gambas, esistono dei metodi, nascosti, che possono essere utilizzati per condizionare la creazione, o meno, dell'oggetto stesso. Questi metodi sono descritti in Metodi nascosti.


Classi virtuali

Tobias Boege, membro della Mailing list ufficiale di Gambas, descrive quanto segue:
«Esistono due tipi di classi virtuali: classi "native" e classi "virtuali" di Gambas.
E' possibile distinguerle approssimativamente dal Componente da cui provengono o dal primo carattere nel loro nome;
* un punto iniziale significa nativo (ad es. .Menu.Children dal Componente nativo gb.qt4 o .Watch.Events da gb.inotify);
* un trattino basso che significa che è scritto in Gambas (ad es. _MapTile in gb.map).
Questa denominazione non è un requisito ma una convenzione.

Una classe virtuale ha lo scopo di fornire un'interfaccia alternativa a una parte di un oggetto. Nei componenti nativi, una proprietà virtuale viene spesso implementata restituendo lo stesso oggetto esatto ma dicendo all'interprete di "eseguirne il cast" in un'altra classe, in modo da disporre di un set di Metodi più specializzato. Molti componenti si basano sul presupposto che possono semplicemente inserire alcuni dati in un campo nella struttura dati sottostante dell'oggetto e restituire se stessi per implementare una proprietà virtuale e che i dati non verranno toccati fino a quando l'oggetto virtuale non viene eseguito.
L'accessorio di proprietà di solito imposta una sorta di flag o registra alcuni parametri di accesso come lo slot delle impostazioni in _Settings_Keys._get () in modo che i metodi più specializzati sappiano dove si vuole che funzionino.
Si può vedere che con il nome delle classi virtuali native: .Menu.Children è una classe virtuale per la gestione della proprietà .Children di un oggetto Menu e .Watch.Events fa lo stesso per .Events di un Watch.
In realtà, le classi virtuali di Gambas (quelle che non sono native) sono solo normali classi. La "fusione di parte di un oggetto in una classe diversa" è una funzionalità strettamente nativa. Probabilmente non dovrebbero nemmeno essere chiamati "virtuali" ma sono spesso usati per lo stesso scopo. Il carattere di sottolineatura principale viene generalmente utilizzato per nascondere le classi, ad es. al popup di completamento automatico IDE. Si potrebbe teoricamente archiviare questi oggetti in un array, ma neanche questo è sicuro, a seconda di quali ipotesi la Classe faccia durante la sua vita.
Ora è possibile vedere il problema: gli oggetti virtuali in realtà non esistono. Sono solo una vista volatile su una parte specifica di un oggetto. Quindi non è possibile porli in un array. Le Classi virtuali possono essere dichiarate nei Componenti nativi, ma non sono creabili e hanno sempre la dimensione zero.

Una Proprietà o un Metodo virtuale consente di eseguire del codice nell'implementazione della proprietà o del metodo, che di solito registra solo alcuni dati nella memoria dell'oggetto e quindi restituisce l'oggetto stesso tramite RETURN_SELF (GB_PROPERTY_SELF è una scorciatoia per restituire se stessi e non fare nulla altro), ma l'interprete considera il valore restituito (sempre lo stesso oggetto) non come del suo vero tipo ma del tipo restituito indicato nella dichiarazione di proprietà.
Improvvisamente, lo stesso oggetto assume un'interfaccia completamente diversa, nuovi metodi, nuove proprietà. Ma è la stessa regione in memoria, quindi le implementazioni di queste nuove proprietà e metodi possono accedere all'oggetto originale. Viene normalmente utilizzato per fornire una vista specializzata sull'oggetto.
Tutto ciò implica, tra l'altro, che non è possibile archiviare oggetti virtuali in memoria, poiché sono solo viste temporanee su un altro oggetto. E l'uso di oggetti virtuali è intrinsecamente pericoloso per i thread poiché, a seconda della rispettiva implementazione, nel processo potrebbe esserci un solo oggetto virtuale per un determinato oggetto reale in qualsiasi momento.

Non è possibile implementare classi virtuali in Gambas. Lo si può fare solo usando l'API C/C ++ nativa dell'interprete, che ha la magia di cambiare un BLOB di descrizione dell'interfaccia con un altro. Tutto ciò che viene scritto in ​​Gambas è una vera classe in cui non si può staccare la memoria dall'interfaccia.
Le classi virtuali sono in realtà solo un trucco nell'interprete per "eseguire il cast parametrico" di un oggetto in un'altra classe per non inquinare, per esempio, l'interfaccia diretta della classe Array con metodi e proprietà correlati ai suoi limiti, poiché quelli possono essere nascosti in un vista virtuale sull'array.
Le classi virtuali consentono di fare ciò:
1) in modo non dispendioso (perché tutto ciò che deve essere fatto è sostituire il puntatore al tipo di un oggetto);
2) senza dover creare nuovi oggetti e quindi creare interfacce della classe originale (semi-) pubblico in modo che questi nuovi oggetti possano accedervi.

Il solito modo di emulare questo in Gambas è:
- creare Classi reali per le viste virtuali, come _Array_Bounds con un Costruttore di _new (RealObject As Array);
- Array.Bounds restituisce una nuova istanza di questo _Array_Bounds e passa il riferimento "Me" al Costruttore;
- la classe Array deve rendere pubblici alcuni interni in modo che _Array_Bounds possa accedervi, essendo ora un oggetto diverso.

Solitamente questi sono preceduti da un trattino basso in modo che l'IDE li nasconda dalle opinioni delle persone normali. »


Un indice delle Classi di Gambas

Nella seguente pagina web è possibile vedere un elenco della Classi di Gambas:

https://www.gambas.one/classes/

Ogni Classe è collegata alla rispettiva pagina della Wiki ufficiale di Gambas.



Note

[1] Bisogna ricordare che un Oggetto non è altro che una Classe istanziata.

oggetto = New Classe

laddove la variabile oggetto è appunto un Oggetto.
Con parola-chiave New viene creato un Oggetto, appartenente ad una specifica Classe, allocando automaticamente la necessaria quantità di memoria richiesta per esso e che così rappresenta la struttura interna dell'Oggetto medesimo.
Infatti, gli "Oggetti" in Gambas sono costituiti da Strutture e Sub-Strutture, scritte in C, che ovviamente occupano memoria.

E' il caso di sottolineare che è un errore l'uso - come argomento di una funzione - di una variabile di un Oggetto che non sia stato creato con la parola New o che non derivi dal ritorno di altra funzione oppure che non sia associata a un Oggetto della medesima Classe.

La variabile che funge da Puntatore a un Oggetto sovente è definita "Handle " (maniglia), che rappresenta "una variabile associata a un oggetto complesso, che lo identifica". La maniglia è la "protuberanza", con la quale si interagisce con l'Oggetto. In Gambas, qualsiasi Oggetto (Form, o altro) è dunque in sostanza un "Handle ". Questo "handle", questa variabile che rappresenta l'Oggetto di una Classe, dunque individua, indica e in certo senso fornisce al programmatore la prima cella di memoria della Struttura principale che costituisce l'Oggetto medesimo.
Questa prima cella di memoria, ove inizia la memoria riservata dal sistema per l'esistenza e la funzionalità dell'Oggetto di una Classe, possiede ovviamente un Indirizzo.
La variabile di un Oggetto, puntando all'area di memoria riservata all'Oggetto, punta dunque a quell'Indirizzo di memoria, si riferisce esplicitamente a quella cella di memoria; anzi esso contiene come valore proprio l'indirizzo di memoria di quella cella.

In Gambas gli Oggetti sono entità individuali concrete di un insieme più ampio, di un Universale che li trascende, chiamato Classe, e che rappresenta per essi un Modello, una Categoria assoluta delle loro caratteristiche (Proprietà, Metodi, Eventi, Variabili e Costanti) possedute che li distinguono dagli Oggetti appartenenti ad altre Classi.
Pertanto gli Oggetti, singolarità di una Classe, per esistere devono, come ogni entità concreta immanente, essere creati.

Una Classe concettualmente è ciò che è comune a più realtà individuali e concrete: gli Oggetti, accomunati tutti dalla circostanza di possedere e di fornire le risorse della Classe, alla quale essi appartengono. La Classe, dunque, è un "insieme" che raggruppa molti elementi individuali - gli Oggetti - che posseggono caratteristiche comuni.
Tali caratteristiche in Gambas possono essere rappresentate dalle seguenti risorse:

  • Proprietà (capacità dell'Oggetto di assumere una qualità);
  • Metodi (capacità dell'Oggetto di compiere un'operazione);
  • Eventi (capacità dell'Oggetto di far accadere qualcosa in caso di una sua sollecitazione);
  • Variabili;
  • Costanti.

La "Classe", dunque, è un sistema organico di risorse tra loro coerenti per la realizzazione di una o più finalità.
La Classe, come già detto, è il modello contenente specifiche caratteristiche (Metodi, Proprietà, Eventi, Variabili e Costanti), al quale fanno riferimento singoli elementi: gli Oggetti. In tal senso gli Oggetti appartengono ad una Classe, ossia sono la rappresentazione concreta delle caratteristiche e delle potenzialità di una Classe. Essi sono gli elementi capaci di fornire concretamente al programmatore ed all'utente le funzionalità della Classe, alla quale essi appartengono. Infatti, la Classe in sé non può essere utilizzata sic et simpliciter all'interno di un codice (ad eccezione delle Classi Statiche), giacché essa solo in astratto possiede alcune specifiche funzionalità. Tali capacità possono essere concretamente utilizzate solo attraverso elementi individuali, gli Oggetti, che alla Classe (astratta) fanno riferimento.
La Classe specifica, dunque, le sue caratteristiche e funzionalità, le quali potranno essere utilizzate e gestite mediante gli Oggetti. In particolare la Proprietà di un Oggetto è un'informazione definibile come attributo dell'Oggetto medesimo.
Tali funzionalità e caratteristiche (Metodi, Proprietà, Eventi, Variabili e Costanti) di una Classe sono tra loro coerenti ed organici alle specificità ed alle potenzialità della Classe, in modo tale che la Classe possa svolgere i compiti, per i quali fu creata.
La Classe è l'elemento astratto, nella quale sono definite determinate funzionalità, compiti e caratteristiche (Metodi, Proprietà, Eventi, Variabili e Costanti); mentre l'Oggetto è l'elemento concreto, virtualmente materiale, utilizzabile nel codice, e che rende possibile l'uso delle potenzialità della Classe, alla quale esso appartiene. In sostanza la Classe è utilizzabile solo attraverso gli Oggetti che ad essa si riferiscono.
La dinamicità della Classe è dovuta anche a questa sua capacità e necessità di esteriorizzarsi, di concretizzarsi in una possibile molteplicità di elementi (gli Oggetti) che ad essa si riferiscono, e che la rendono così effettivamente utilizzabile nel codice e, dunque, nel programma.
Tale non staticità di una "Classe" consente al programmatore di creare più Oggetti di essa (questa facoltà non è consentita ad esempio per le Classi statiche e per i Moduli che sono "statici" per propria natura).

Per comprendere a pieno il concetto di "istanza" di una Classe, è opportuno comprendere l'etimo della parola, che proveniendo dal latino "in + sto", vuol significare "stare in", e quindi "stare nel (mondo)", "starci", "esistere nella (realtà)". Una Classe in quanto modello non esiste nel/sul mondo, ossia concretamente, è semplicemente un predicato astratto, un paradigma. Se la Classe si fa concreta, si in-stanzia, ossia si in-pone nella realtà concreta del programma, diventa gestibile in modo effettivo, virtualmente tangibile: diventa insomma un "Oggetto". L'Oggetto si pone, sta nel mondo del programma informatico con una sua individualità, definita e condizionata da funzionalità e caratteristiche che rimandano necessariamente alla sua Classe di appartenenza.

Per accedere all'uso delle risorse (Metodi, Proprietà, Eventi, Variabili e Costanti) di una Classe si adopererà l'operatore "." che distingue la variabile - identificatrice dell'Oggetto costruito - dalla sua risorsa, specificandone nello stesso tempo tipo e appartenenza:

nome_variabile.nome_risorsa

[2] Vedere anche le seguenti discussioni sul forum:
- https://www.gambas-it.org/smf/index.php?topic=933.0
- https://www.gambas-it.org/smf/index.php?topic=242

[3] Minisini, rispondendo nella Mailing List ufficiale di Gambas, ha così brevemente definito il Modulo:

"A module is just a class whose all methods and properties are static.
It's a thing coming from Visual Basic.
It's like a class, except everything is static.
It's static, that means it cannot be instantiated."

Va ricordato che a una Classe statica o a un Modulo (che è di per sé statico) si può accedere senza bisogno di creare un'istanza della Classe o del Modulo.

[4] Un Modulo non può essere istanziato, non può creare il proprio Osservatore, né può sollevare direttamente un Evento mediante l'istruzione "Event". Per tanto un Modulo può solo “partecipare” agli Eventi pubblici di altre Classi.

[5] La Parola-Chiave è una parola riservata del linguaggio di programmazione, che di norma non può essere utilizzata diversamente da ciò per cui è stata concepita.
Per esempio nella riga:

Dim variabile As Integer

la parola "Dim" è una parola-chiave, mentre non lo è la parola "variabile".

In vero, però, in Gambas una parola-chiave può essere utilizzata come identificativa di una variabile, purché posta fra due parentesi graffe:

Dim {Dim} As Integer

{Dim} = 100000
 
Print {Dim}


Riferimenti