Oppure

Loading

Bene bene. Eccoci arrivati al sugo della questione. Le classi, entità alla base di tutto l'edificio del .NET. Già nei primi capitoli di questa guida ho accennato alle classi, alla loro sintassi e al modo di dichiararle. Per chi non si ricordasse (o non avesse voglia di lasciare questa magnifica pagina per ritornare indietro nei capitoli), una classe si dichiara semplicemente così:
Class [Nome Classe]
    '...
End Class 
Con l'atto della dichiarazione, la classe inizia ad esistere all'interno del codice sorgente, cosicchè il programmatore la può usare in altre parti del listato per gli scopi a causa dei quali è stata creata. Ora che ci stiamo avvicinando sempre più all'usare le classi nei prossimi programmi, tuttavia, è doveroso ricordare ancora una volta la sostanziale differenza tra dichiarazione e inizializzazione, tra classe e oggetto, giusto per rinfrescare le memorie più fragili e, lungi dal farvi odiare questo concetto, per fare in modo che il messaggio penetri:
Module Module1
    'Classe che rappresenta un cubo.
    'Segue la dichiarazione della classe. Da questo momento
    'in poi, potremo usare Cube come tipo per le nostre variabili.
    'Notare che una classe si dichiara e basta, non si 
    '"inizializza", perchè non è qualcosa di concreto, 
    'è un'astrazione, c'è, esiste in generale.
    Class Cube
        'Variabile che contiene la lunghezza del lato
        Dim SideLength As Single
        'Variabile che contiene la densità del cubo, e quindi
        'ci dice di che materiale è composto
        Dim Density As Single

        'Questa procedura imposta i valori del lato e 
        'della densità
        Sub SetData(ByVal SideLengthValue As Single, ByVal DensityValue As Single)
            SideLength = SideLengthValue
            Density = DensityValue
        End Sub

        'Questa funzione restituisce l'area di una faccia
        Function GetSurfaceArea() As Single
            Return (SideLength ^ 2)
        End Function

        'Questa funzione restituisce il volume del cubo
        Function GetVolume() As Single
            Return (SideLength ^ 3)
        End Function

        'Questa funzione restituisce la massa del cubo
        Function GetMass() As Single
            Return (Density * GetVolume())
        End Function
    End Class

    Sub Main()
        'Variabile di tipo Cube, che rappresenta uno specifico cubo
        'La riga di codice che segue contiene la dichiarazione
        'della variabile A. La dichiarazione di una variabile
        'fa sapere al compilatore, ad esempio, di che tipo
        'sarà, in quale blocco di codice sarà
        'visibile, ma nulla di più.
        'Non esiste ancora un oggetto Cube collegato ad A, ma
        'potrebbe essere creato in un immediato futuro.
        'N.B.: quando si dichiara una variabile di tipo reference,
        'viene comunque allocata memoria sullo stack; viene
        'infatti creato un puntatore, che punta all'oggetto
        'Nothing, il cui valore simbolico è stato
        'spiegato precedentemente.
        Dim A As Cube

        'Ed ecco l'immediato furuto: con la prossima linea di
        'codice, creiamo l'oggetto di tipo Cube che verrà
        'posto nella variabile A.
        A = New Cube
        'Quando New è seguito dal nome di una classe, si crea un
        'oggetto di quel tipo. Nella fattispecie, in questo momento
        'il programma si preoccuperà di richiedere della
        'memoria sull'heap managed per allocare i dati relativi
        'all'oggetto e di creare un puntatore sullo stack che
        'punti a tale oggetto. Esso, inoltre, eseguirà
        'il codice contenuto nel costruttore. New, infatti,
        'è uno speciale tipo di procedura, detta
        'Costruttore, di cui parlerò approfonditamente
        'in seguito

        'Come per le strutture, i membri di classe sono accessibili
        'tramite l'operatore punto ".". Ora imposto le variabili
        'contenute in A per rappresentare un cubo di alluminio
        '(densità 2700 Kg/m3) di 1.5m di lato
        A.SetData(1.5, 2700)

        Console.WriteLine("Superficie faccia: " & A.GetSurfaceArea() & " m2")
        Console.WriteLine("Volume: " & A.GetVolume() & " m3")
        Console.WriteLine("Massa: " & A.GetMass() & " Kg")
        'Pesa quasi una tonnellata!!

        Console.ReadKey()
    End Sub
End Module 
In questo esempio ho usato una semplice classe che rappresenta un cubo di una certa dimensione e di un certo materiale. Tale classe espone quattro funzioni, che servono per ottenere informazioni o impostare valori. C'è un preciso motivo per cui non ho usato direttamente le due variabili accedendovi con l'operatore punto, e lo spiegherò a breve nella prossima lezione. Quindi, tali funzioni sono membri di classe e, soprattutto, funzioni di istanza. Questo lemma non dovrebbe suonarvi nuovo: gli oggetti, infatti, sono istanze (copie materiali, concrete) di classi (astrazioni). Anche questo concetto è molto importante: il fatto che siano "di istanza" significa che possono essere richiamate ed usate solo da un oggetto. Per farvi capire, non si possono invocare con questa sintassi:
Cube.GetVolume() 
ma solo passando attraverso un'istanza:
Dim B As New Cube
'...
B.GetVolume() 
E questo, tra l'altro, è abbastanza banale: infatti, come sarebbe possibile calcolare area, volume e massa se non si disponesse della misura della lunghezza del lato e quella della densità? È ovvio che ogni cubo ha le sue proprie misure, e il concetto generale di "cubo" non ci dice niente su queste informazioni.


Un semplice costruttore

Anche se entreremo nel dettaglio solo più in là, è necessario per i prossimi esempi che sappiate come funziona un costruttore, anche molto semplice. Esso viene dichiarato come una normale procedura, ma si deve sempre usare come nome "New":
Sub New([parametri])
    'codice
End Sub 
Qualora non si specificasse nessun costruttore, il compilatore ne creerà uno nuovo senza parametri, che equivale al seguente:
Sub New()
End Sub 
Il codice presente nel corpo del costruttore viene eseguito in una delle prime fasi della creazione dell'oggetto, appena dopo che questo è statao fisicamente collocato nella memoria (ma, badate bene, non è la prima istruzione ad essere eseguita dopo la creazione). Lo scopo di tale codice consiste nell'inizializzare variabili di tipo reference prima solo dichiarate, attribuire valori alle variabili value, eseguire operazioni di preparazione all'uso di risorse esterne, eccetera... Insomma, serve a spianare la strada all'uso della classe. In questo caso, l'uso che ne faremo è molto ridotto e, non vorrei dirlo, quasi marginale, ma è l'unico compito possibile e utile in questo contesto: daremo al costruttore il compito di inizializzare SideLength e Density.
Module Module1
    Class Cube
        Dim SideLength As Single
        Dim Density As Single

        'Quasi uguale a SetData
        Sub New(ByVal SideLengthValue As Single, ByVal DensityValue As Single)
            SideLength = SideLengthValue
            Density = DensityValue
        End Sub

        Function GetSurfaceArea() As Single
            Return (SideLength ^ 2)
        End Function

        Function GetVolume() As Single
            Return (SideLength ^ 3)
        End Function

        Function GetMass() As Single
            Return (Density * GetVolume())
        End Function
    End Class

    Sub Main()
        'Questa è una sintassi più concisa che equivale a:
        'Dim A As Cube
        'A = New Cube(2700, 1.5)
        'Tra parentesi vanno passati i parametri richiesti dal
        'costruttore
        Dim A As New Cube(2700, 1.5)

        Console.WriteLine("Superficie faccia: " & A.GetSurfaceArea() & " m2")
        Console.WriteLine("Volume: " & A.GetVolume() & " m3")
        Console.WriteLine("Massa: " & A.GetMass() & " Kg")
        
        Console.ReadKey()
    End Sub
End Module 


Una nota sulle Strutture

Anche le strutture, come le classi, possono esporre procedure e funzioni, e questo non è strano. Esse, inoltre, possono esporre anche costruttori... e questo dovrebbe apparirvi strano. Infatti, ho appena illustrato l'importanza dei costruttori nell'istanziare oggetti, quindi tipi reference, mentre le strutture sono palesemente tipi value. Il conflitto si risolve con una soluzione molto semplice: i costruttori dichiarati nelle strutture possono essere usati esattamente come per le classi, ma il loro compito è solo quello di inizializzare campi e richiamare risorse, poiché una variabile di tipo strutturato viene creata sullo stack all'atto della sua dichiarazione.
Module Module1
    Structure Cube
        Dim SideLength As Single
        Dim Density As Single

        Sub New(ByVal SideLengthValue As Single, ByVal DensityValue As Single)
            SideLength = SideLengthValue
            Density = DensityValue
        End Sub

        Function GetSurfaceArea() As Single
            Return (SideLength ^ 2)
        End Function

        Function GetVolume() As Single
            Return (SideLength ^ 3)
        End Function

        Function GetMass() As Single
            Return (Density * GetVolume())
        End Function
    End Structure

    Sub Main()
        'Questo codice
        Dim A As New Cube(2700, 1.5)

        'Equivale a questo
        Dim B As Cube
        B.SideLength = 1.5
        B.Density = 2700

        'A e B sono uguali

        Console.ReadKey()
    End Sub
End Module 


A cura di: Il Totem