Shadowing in Visual Basic
Quando due elementi di programmazione condividono lo stesso nome, uno di essi può nascondere l'altro, o eseguirne lo shadowing. In tale situazione, l'elemento nascosto non è disponibile come riferimento. Quando invece il codice usa il nome dell'elemento, il compilatore Visual Basic lo risolve nell'elemento di shadowing.
Scopo
Lo scopo principale dello shadowing è proteggere la definizione dei membri della classe. La classe di base potrebbe subire una modifica che crea un elemento con lo stesso nome di quello già definito. In questo caso, il modificatore Shadows
forza la risoluzione dei riferimenti tramite la classe al membro definito, anziché al nuovo elemento della classe di base.
Tipi di shadowing
Un elemento può nascondere un altro elemento in due modi diversi. L'elemento di shadowing può essere dichiarato all'interno di un'area secondaria dell'area contenente l'elemento nascosto, nel qual caso lo shadowing viene eseguito tramite ambito. In alternativa, una classe derivata può ridefinire un membro di una classe di base, nel qual caso lo shadowing viene eseguito tramite ereditarietà.
Shadowing tramite ambito
È possibile che gli elementi di programmazione nello stesso modulo, classe o struttura abbiano lo stesso nome ma un ambito diverso. Quando due elementi vengono dichiarati in questo modo e il codice fa riferimento al nome che condividono, l'elemento con l'ambito più ristretto nasconde l'altro elemento (l'ambito blocco è il più ristretto).
Ad esempio, un modulo può definire una variabile Public
denominata temp
e una routine all'interno del modulo può dichiarare una variabile locale anch'essa denominata temp
. I riferimenti a temp
dall'interno della routine accedono alla variabile locale, mentre i riferimenti a temp
dall'esterno della routine accedono alla variabile Public
. In questo caso, la variabile temp
della routine nasconde la variabile temp
del modulo.
La figura seguente mostra due variabili, entrambe denominate temp
. La variabile locale temp
nasconde la variabile membro temp
quando vi si accede dall'interno della propria routine p
. Tuttavia, la parola chiave MyClass
ignora lo shadowing e accede alla variabile membro.
Per un esempio di shadowing tramite ambito, vedere Procedura: Nascondere una variabile con lo stesso nome di un'altra variabile.
Shadowing tramite ereditarietà
Se una classe derivata ridefinisce un elemento di programmazione ereditato da una classe di base, l'elemento di ridefinizione nasconde l'elemento originale. È possibile nascondere qualsiasi tipo di elemento dichiarato o set di elementi di overload con qualsiasi altro tipo. Ad esempio, una variabile Integer
può nascondere una routine Function
. Se si nasconde una routine con un'altra routine, è possibile utilizzare un elenco di parametri diverso e un tipo restituito diverso.
La figura seguente illustra una classe di base b
e una classe derivata d
che eredita da b
. La classe di base definisce una routine denominata proc
e la classe derivata la nasconde con un'altra routine con lo stesso nome. La prima istruzione Call
accede allo shadowing proc
nella classe derivata. Tuttavia, la parola chiave MyBase
ignora lo shadowing e accede alla routine nascosta nella classe di base.
Per un esempio di shadowing tramite ereditarietà, vedere Procedura: Nascondere una variabile con lo stesso nome di un'altra variabile e Procedura: Nascondere una variabile ereditata.
Shadowing e livello di accesso
L'elemento di shadowing non è sempre accessibile dal codice usando la classe derivata. Ad esempio, potrebbe essere dichiarato Private
. In questo caso, lo shadowing viene annullato e il compilatore risolve qualsiasi riferimento allo stesso elemento che avrebbe avuto se non ci fosse stato lo shadowing. Questo elemento è l'elemento accessibile con il minor numero di passaggi derivazionali all'indietro dalla classe di shadowing. Se l'elemento nascosto è una routine, la risoluzione corrisponde alla versione accessibile più vicina con lo stesso nome, elenco di parametri e tipo restituito.
Nell'esempio seguente viene illustrata una gerarchia di ereditarietà di tre classi. Ogni classe definisce una routine Sub
display
e ogni classe derivata nasconde la routine display
nella relativa classe di base.
Public Class firstClass
Public Sub display()
MsgBox("This is firstClass")
End Sub
End Class
Public Class secondClass
Inherits firstClass
Private Shadows Sub display()
MsgBox("This is secondClass")
End Sub
End Class
Public Class thirdClass
Inherits secondClass
Public Shadows Sub display()
MsgBox("This is thirdClass")
End Sub
End Class
Module callDisplay
Dim first As New firstClass
Dim second As New secondClass
Dim third As New thirdClass
Public Sub callDisplayProcedures()
' The following statement displays "This is firstClass".
first.display()
' The following statement displays "This is firstClass".
second.display()
' The following statement displays "This is thirdClass".
third.display()
End Sub
End Module
Nell'esempio precedente la classe derivata secondClass
nasconde display
con una routine Private
. Quando il modulo callDisplay
chiama display
in secondClass
, il codice chiamante si trova al di fuori di secondClass
e pertanto non può accedere alla routine privata display
. Lo shadowing viene annullato e il compilatore risolve il riferimento alla routine display
della classe di base.
Tuttavia, l'ulteriore classe derivata thirdClass
dichiara display
come Public
, quindi il codice in callDisplay
può accedervi.
Shadowing e override
Non bisogna confondere lo shadowing con l'override. Entrambi vengono usati quando una classe derivata eredita da una classe di base ed entrambi ridefiniscono un elemento dichiarato con un altro. Esistono tuttavia differenze significative tra i due. Per un confronto, vedere Differenze tra shadowing e override.
Shadowing e overload
Se si nasconde lo stesso elemento della classe di base con più di un elemento nella classe derivata, gli elementi di shadowing diventano versioni di overload di tale elemento. Per altre informazioni, vedere Procedure Overloading.
Accesso a un elemento nascosto
Quando si accede a un elemento da una classe derivata, in genere si esegue questa operazione tramite l'istanza corrente di tale classe derivata qualificando il nome dell'elemento con la parola chiave Me
. Se la classe derivata nasconde l'elemento nella classe di base, è possibile accedere all'elemento della classe di base qualificandolo con la parola chiave MyBase
.
Per un esempio di accesso a un elemento nascosto, vedere Procedura: Accedere a una variabile nascosta da una classe derivata.
Dichiarazione della variabile oggetto
La modalità di creazione della variabile oggetto può influire anche sul fatto che la classe derivata acceda a un elemento di shadowing o all'elemento nascosto. Nell'esempio seguente vengono creati due oggetti da una classe derivata, ma un oggetto viene dichiarato come classe di base e l'altro come classe derivata.
Public Class baseCls
' The following statement declares the element that is to be shadowed.
Public z As Integer = 100
End Class
Public Class dervCls
Inherits baseCls
' The following statement declares the shadowing element.
Public Shadows z As String = "*"
End Class
Public Class useClasses
' The following statement creates the object declared as the base class.
Dim basObj As baseCls = New dervCls()
' Note that dervCls widens to its base class baseCls.
' The following statement creates the object declared as the derived class.
Dim derObj As dervCls = New dervCls()
Public Sub showZ()
' The following statement outputs 100 (the shadowed element).
MsgBox("Accessed through base class: " & basObj.z)
' The following statement outputs "*" (the shadowing element).
MsgBox("Accessed through derived class: " & derObj.z)
End Sub
End Class
Nell'esempio precedente la variabile basObj
viene dichiarata come classe di base. L'assegnazione di un oggetto dervCls
a tale variabile costituisce una conversione che supporta un maggior numero di dati ed è pertanto valida. Tuttavia, la classe di base non può accedere alla versione shadowing della variabile z
nella classe derivata, quindi il compilatore risolve basObj.z
nel valore origine della classe di base.