Sombrear en Visual Basic
Cuando dos elementos de programación comparten el mismo nombre, uno de ellos puede ocultar, o sombrear, al otro. En esta situación, el elemento sombreado no está disponible para referencia; en su lugar, cuando el código usa el nombre del elemento, el compilador de Visual Basic lo resuelve en el elemento que realiza el sombreado.
Propósito
El objetivo principal del sombreado es proteger la definición de los miembros de la clase. La clase base puede sufrir un cambio que crea un elemento con el mismo nombre que el que ya ha definido. Si esto sucede, el modificador Shadows
obliga a que las referencias a través de la clase se resuelvan en el miembro definido, en lugar de en el nuevo elemento de la clase base.
Tipos de sombreado
Un elemento puede sombrear a otro elemento de dos maneras diferentes. El elemento que realiza el sombreado se puede declarar dentro de una subdivisión de la región que contiene el elemento sombreado, en cuyo caso el sombreado se realiza mediante el ámbito. O bien, una clase derivada puede redefinir un miembro de una clase base, en cuyo caso el sombreado se realiza mediante herencia.
Sombreado mediante el ámbito
Es posible que los elementos de programación de un mismo módulo, clase o estructura tengan el mismo nombre, pero un ámbito diferente. Cuando se declaran dos elementos de esta manera y el código hace referencia al nombre que comparten, el elemento con el ámbito más limitado sombrea al otro elemento (el ámbito de bloque es el más limitado).
Por ejemplo, un módulo puede definir una variable Public
denominada temp
y un procedimiento dentro del módulo puede declarar una variable local también denominada temp
. Las referencias a temp
desde dentro del procedimiento acceden a la variable local, mientras que las referencias a temp
desde fuera del procedimiento acceden a la variable Public
. En este caso, la variable de procedimiento temp
sombrea a la variable de módulo temp
.
En la ilustración siguiente se muestran dos variables, ambas denominadas temp
. La variable local temp
sombre a la variable de miembro temp
cuando se accede desde su propio procedimiento p
. Sin embargo, la palabra clave MyClass
omite el sombreado y accede a la variable de miembro.
Para obtener un ejemplo de sombreado mediante el ámbito, consulte Cómo: Ocultar una variable con el mismo nombre que su variable.
Sombreado mediante herencia
Si una clase derivada vuelve a definir un elemento de programación heredado de una clase base, el elemento redefinido sombrea al elemento original. Puede sombrear cualquier tipo de elemento declarado, o conjunto de elementos sobrecargados, con cualquier otro tipo. Por ejemplo, una variable Integer
puede sombrear un procedimiento Function
. Si sombre un procedimiento con otro procedimiento, puede usar una lista de parámetros diferente y otro tipo de valor devuelto.
En la ilustración siguiente se muestra una clase base b
y una clase derivada d
que se hereda de b
. La clase base define un procedimiento denominado proc
y la clase derivada lo sombrea con otro procedimiento del mismo nombre. La primera instrucción Call
accede al procedimiento proc
que realiza el sombreado en la clase derivada. Sin embargo, la palabra clave MyBase
omite este procedimiento y accede al procedimiento sombreado en la clase base.
Para obtener un ejemplo de sombreado mediante herencia, consulte Cómo: Ocultar una variable con el mismo nombre que su variable y Cómo: Ocultar una variable heredada.
Sombreado y nivel de acceso
El elemento que realiza el sombreado no siempre es accesible desde el código mediante la clase derivada. Por ejemplo, podría declararse Private
. En tal caso, el sombreado se anula y el compilador resuelve cualquier referencia al mismo elemento como lo haría si no existiese el sombreado. Este elemento es el elemento accesible con menos pasos de derivación hacia atrás desde la clase que realiza el sombreado. Si el elemento sombreado es un procedimiento, la resolución es a la versión accesible más cercana con el mismo nombre, lista de parámetros y tipo de valor devuelto.
En el ejemplo siguiente se muestra una jerarquía de herencia de tres clases. Cada clase define un Sub
procedimiento display
y cada clase derivada sombrea el procedimiento display
de su clase 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
En el ejemplo anterior, la clase derivada secondClass
sombrea display
por un procedimiento Private
. Cuando el módulo callDisplay
llama a display
en secondClass
, el código de llamada está fuera de secondClass
y, por lo tanto, no puede acceder al procedimiento privado display
. El sombreado se anula y el compilador resuelve la referencia al procedimiento display
de la clase base.
Sin embargo, la clase derivada thirdClass
adicional declara display
como Public
, por lo que el código de callDisplay
puede acceder a él.
Sombreado y reemplazos
No confunda el sombreado con el reemplazo. Ambas funciones se utilizan cuando una clase derivada se hereda de una clase base, y ambas redefinen un elemento declarado con otro. Pero existen diferencias significativas entre las dos. Para ver una comparación, consulte Diferencias entre sombrear y reemplazar.
Sombreado y sobrecarga.
Si sombrea el mismo elemento de la clase base con más de un elemento de la clase derivada, los elementos de sombreado se transforman en versiones sobrecargadas de ese elemento. Para obtener más información, consulta Procedure Overloading.
Acceso a un elemento sombreado
Cuando accede a un elemento de una clase derivada, normalmente lo hace a través de la instancia actual de esa clase derivada, habilitando el nombre del elemento con la palabra clave Me
. Si la clase derivada sombrea el elemento de la clase base, para acceder al elemento de la clase base puede habilitarlo con la palabra clave MyBase
.
Para obtener un ejemplo de acceso a un elemento sombreado, consulte Cómo: Obtener acceso a una variable que oculta una clase derivada.
Declaración de la variable de objeto
La forma en que se crea la variable de objeto también puede afectar a si la clase derivada accede al elemento que sombrea o al que es sombreado. En el ejemplo siguiente se crean dos objetos a partir de una clase derivada, pero un objeto se declara como la clase base y el otro como la clase derivada.
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
En el ejemplo anterior, la variable basObj
se declara como la clase base. Asignarle un objeto dervCls
a ella constituye una conversión de ampliación y, por tanto, es válido. Sin embargo, la clase base no puede acceder a la versión que efectúa el sombreado de la variable z
en la clase derivada, por lo que el compilador resuelve basObj.z
en el valor de la clase base original.