Casino online











Mercato forex






A29. Ereditarietà


L'ereditarietà è la possibilità di un linguaggio ad oggetti di far derivare una classe da un'altra: in questo caso, la classe derivata acquisisce tutti i membri della classe base, ma può ridefinirli (se vuole) o aggiungerne di nuovi. Questa caratteristica di ogni linguaggio Object Oriented è particolarmente efficace nello schematizzare una relazione "is-a" (ossia "è un"). Per esempio, potremmo definire una classe Vegetale, quindi una nuova classe Fiore, che eredita Vegetale. Fiore è un Vegetale, come mostra la struttura gerarchica dell'ereditarietà. Se definissimo un'altra classe Primula, derivata da Fiore, diremmo che Primula è un Fiore, che a sua volta è un Vegetale. Quest'ultimo tipo di relazione, che crea classi derivate che saranno basi per ereditare altre classi, si chiama ereditarietà indiretta.
Passiamo ora a vedere come si dichiara una classe derivata:
Class [Nome]
  Inherits [Classe base]
  'Membri della classe
End Class 
La keyword Inherits specifica quale classe base ereditare: si può avere solo una direttiva Inherits per classe, ossia non è possibile ereditare più classi base. In questo frangente, si può scoprire come le proprietà siano utili e flessibili: se una classe base definisce una variabile pubblica, questa diverrà parte anche della classe derivata e su tale variabile verranno basate tutte le operazioni che la coinvolgono. Siccome è possibile che la classe derivata voglia ridefinire tali operazioni e molto probabilmente anche l'utilizzo della variabile, è sempre consigliabile dichiarare campi Private avvolti da una proprietà, poichè non c'è mai alcun pericolo nel modificare una proprietà in classi derivate, ma non è possibile modificare i campi nella stessa classe. Un semplice esempio di ereditarietà:
Class Person
    'Per velocizzare la scrittura del codice, assumiamo che
    'questi campi pubblici siano proprietà
    Public FirstName, LastName As String

    Public ReadOnly Property CompleteName() As String
        Get
            Return FirstName & " " & LastName
        End Get
    End Property
End Class

'Lo studente, ovviamente, è una persona
Class Student
    'Student eredita da Person
    Inherits Person

    'In più, definisce anche questi campi pubblici
    'La scuola frequentata
    Public School As String
    'E l'anno di corso
    Public Year As Byte
End Class 
In seguito, si può utilizzare la classe derivata come si è sempre fatto, con ogni altra classe: bisogna notare che questa può richiamare anche i membri della classe base, ma solo in relazione allo specificatore di accesso. Infatti, esistono delle regole nell'ereditarietà, che vengono applicate nell'azione di ereditare per cambiare l'ambito di visibilità di un membro.
  • Un membro Public o Friend della classe base diventa un membro Public o Friend della classe derivata
  • Un membro Private della classe base non è accessibile dalla classe derivata, poichè il suo ambito di visibilità impedisce a ogni chiamante esterno alla classe base di farvi riferimento, come già visto nelle lezioni precedenti
  • Un membro Protected della classe base diventa un membro Protected della classe derivata, ma si comporta come un membro Private
Il nuovo specificatore di accesso Protected appena visto è speciale: se un membro viene dichiarato in questo modo, si comporta a tutti gli effetti come Private; tuttavia, poichè i Private non possono essere ereditati, costituisce una scappatoia alla questione, in quanto Protected diventa ugualmente Protected nella classe derivata. Lo specificatore Protected friend, invece, rende un membro o una classe nidificata visibile sia alla classe che lo/la contiene sia a ogni parte dell'assembly corrente: questo è utile in quanto le classi nidificate devono in alternativa essere sempre dichiarate Private. Esempio:
Module Esempio
    Class Person
        'Due campi protected
        Protected _FirstName, _LastName As String
        'Un campo private readonly: non c'è ragione di rendere
        'questo campo Protected poichè la data di nascita non
        'cambia ed è sempre accessibile tramite la proprietà
        'pubblica BirthDay
        Private ReadOnly _BirthDay As Date

        Public Property FirstName() As String
            Get
                Return _FirstName
            End Get
            Set(ByVal Value As String)
                If Value <> "" Then
                    _FirstName = Value
                End If
            End Set
        End Property

        Public Property LastName() As String
            Get
                Return _LastName
            End Get
            Set(ByVal Value As String)
                If Value <> "" Then
                    _LastName = Value
                End If
            End Set
        End Property

        Public ReadOnly Property BirthDay() As Date
            Get
                Return _BirthDay
            End Get
        End Property

        Public ReadOnly Property CompleteName() As String
            Get
                Return _FirstName & " " & _LastName
            End Get
        End Property

        'Costruttore che accetta tra parametri obbligatori
        Sub New(ByVal FirstName As String, ByVal LastName As String, _
            ByVal BirthDay As Date)
            Me.FirstName = FirstName
            Me.LastName = LastName
            Me._BirthDay = BirthDay
        End Sub
    End Class

    'Lo studente, ovviamente, è una persona
    Class Student
        'Student eredita da Person
        Inherits Person

        'La scuola frequentata
        Private _School As String
        'E l'anno di corso
        Private _Year As Byte

        Public Property School() As String
            Get
                Return _School
            End Get
            Set(ByVal Value As String)
                If Value <> "" Then
                    _School = Value
                End If
            End Set
        End Property

        Public Property Year() As Byte
            Get
                Return _Year
            End Get
            Set(ByVal Value As Byte)
                If Value > 0 Then
                    _Year = Value
                End If
            End Set
        End Property

        'Questa nuova proprietà si serve anche dei campi FirstName
        'e LastName nel modo corretto, poichè sono Protected anche nella
        'classe derivata e fornisce un profilo completo dello studente
        Public ReadOnly Property Profile() As String
            Get
                'Da notare l'accesso a BirthDay tramite la proprietà
                'Public: non è possibile accedere al campo _BirthDay
                'perchè è privato nella classe base
                Return _FirstName & " " & _LastName & ", nato il " & _
                BirthDay.ToShortDateString & " frequenta l'anno " & _
                _Year & " alla scuola " & _School
            End Get
        End Property

        'Altra clausola importante: il costruttore della classe derivata 
        'deve sempre richiamare il costruttore della classe base
        Sub New(ByVal FirstName As String, ByVal LastName As String, _ 
            ByVal BirthDay As Date, ByVal School As String, _
            ByVal Year As Byte)
            MyBase.New(FirstName, LastName, BirthDay)
            Me.School = School
            Me.Year = Year
        End Sub
    End Class

    Sub Main()
        Dim P As New Person("Pinco", "Pallino", Date.Parse("06/07/90"))
        Dim S As New Student("Tizio", "Caio", Date.Parse("23/05/92"), _
        "Liceo Classico Ugo Foscolo", 2)

        Console.WriteLine(P.CompleteName)
        'Come si vede, la classe derivata gode degli stessi membri 
        'di quella base, acquisiti secondo le regole dell'ereditarietà 
        'appena spiegate
        Console.WriteLine(S.CompleteName)
        'E in più ha anche i suoi nuovi membri
        Console.WriteLine(S.Profile)

        'Altra cosa interessante: dato che Student è derivata da 
        'Person ed espone tutti i membri di Person, più altri, non è 
        'sbagliato assegnare un oggetto Student a una variabile Person
        P = S
        Console.WriteLine(P.CompleteName)

        Console.ReadKey()
    End Sub
End Module 
L'output:
Pinco Pallino
Tizio Caio
Tizio Caio, nato il 23/5/1992 frequenta l'anno 2 alla scuola Liceo Classico Ugo 
Foscolo
Tizio Caio 
(Per maggiori informazioni sulle operazioni con le date, vedere il capitolo 57)
Anche se il sorgente è ampiamente commentato mi soffermerei su alcuni punti caldi. Il costruttore della classe derivata deve sempre richiamare il costruttore della classe base, e questo avviene tramite la keyword MyBase che, usata in una classe derivata, fa riferimento alla classe base corrente: attraverso questa parola riservata è possibile anche raggiungere i membri privati della classe base, ma si fa raramente, poichè il suo impiego più frequente è quello di riprendere le vecchie versioni di metodi modificati. Il secondo punto riguarda la conversione di classi: passare da Student a Person non è, come potrebbe sembrare, una conversione di riduzione, poichè durante il processo, nulla va perduto nel vero senso della parola. Certo, si perdono le informazioni supplementari, ma alla classe base queste non servono: la sicurezza di eseguire la conversione risiede nel fatto che la classe derivata gode degli stessi membri di quella base e quindi non si corre il rischio che ci sia riferimento a un membro inesistente. Questo invece si verifica nel caso opposto: se una variabile di tipo Student assumesse il valore di un oggetto Person, School e Year sarebbero privi di valore e ciò generebbe un errore. Per eseguire questo tipo di passaggi è necessario l'operatore DirectCast.




 

The Totem's Lair - Copyright (C) 2009
È vietata la riproduzione sia totale che parziale del sito.