Sombrear en Visual Basic
Actualización: noviembre 2007
Si 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 como referencia; en vez de esto, cuando el código utiliza el nombre del elemento, el compilador de Visual Basic resuelve en favor del elemento que sombrea.
Finalidad
La finalidad principal de sombrear es proteger la definición de los miembros de la clase. La clase base puede sufrir un cambio que cree un elemento con el mismo nombre que otro ya definido. Si sucede esto, el modificador Shadows fuerza a referencias a través de la clase para que se resuelvan en el miembro definido en lugar de hacerlo en el nuevo elemento de la clase base.
Tipos de sombreado
Un elemento puede sombrear a otro de dos formas. El elemento que sombrea puede declararse dentro de una subregión de la región que contiene el elemento sombreado, en cuyo caso el sombreado se consigue por ámbito. O bien, una clase derivada puede redefinir un miembro de una clase base, en cuyo caso el sombreado se consigue por herencia.
Sombreado por ámbito
Es posible que los elementos de programación del mismo módulo, clase o estructura tengan un nombre idéntico pero ámbitos diferentes. Si dos elementos se declaran de esta manera y el código hace referencia al nombre que comparten, el elemento de ámbito más restringido oculta al otro elemento (el ámbito de bloque es el más restringido).
Por ejemplo, un módulo puede definir una variable Public denominada temp y un procedimiento contenido en el módulo puede declarar una variable local con el mismo nombre temp. Las referencias al nombre temp desde dentro del procedimiento obtienen acceso a la variable local, mientras que las referencias a temp desde fuera del procedimiento obtienen acceso a la variable Public. En este caso, la variable de procedimiento temp ensombrece a la variable de módulo temp.
La ilustración siguiente muestra dos variables, los dos denominadas temp. La variable local temp sombrea la variable miembro temp cuando se tiene acceso a ella desde su propio procedimiento p. Sin embargo, la palabra clave MyClass omite el sombreado y tiene acceso a la variable miembro.
Sombreado por ámbito
Para obtener un ejemplo de sombreado por ámbito, consulte Cómo: Ocultar una variable con el mismo nombre que su variable.
Sombreado por herencia
Si una clase derivada vuelve a definir un elemento de programación heredado de una clase base, el elemento que redefine ensombrece al elemento original. Se 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 sombrea un procedimiento con otro, puede utilizar una lista de parámetros distinta y un tipo de devolución distinto.
La ilustración siguiente muestra una clase base b y una clase derivada d que 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 tiene acceso al sombreado proc en la clase derivada. Sin embargo, la palabra clave MyBase omite el sombreado y tiene acceso al procedimiento sombreado en la clase base.
Sombreado por herencia
Para obtener un ejemplo de sombreado por 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 de sombreado no siempre es accesible desde el código que utiliza la clase derivada. Por ejemplo, se podría declarar Private. En este caso, se rechaza el sombreado y el compilador resuelve cualquier referencia en el mismo elemento que tendría si no hubiera habido sombreado. Éste es el elemento accesible con menos pasos de derivación en sentido inverso desde la clase que sombrea. Si el elemento sombreado es un procedimiento, la resolución se concreta en la versión accesible más próxima con el mismo nombre, lista de parámetros y tipo de valor devuelto.
El ejemplo siguiente muestra una jerarquía de herencia de tres clases. Cada clase define un procedimiento Subdisplay y cada clase derivada sombrea el procedimiento display en 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 con un procedimiento Private. Cuando el módulo callDisplay llama a display en secondClass, el código de llamada está fuera de secondClass y no puede tener acceso al procedimiento display privado. Se rechaza el sombreado y el compilador resuelve la referencia en el procedimiento display de la clase base.
Sin embargo, la siguiente clase derivada thirdClass declara display como Public, por lo que el código de callDisplay puede tener acceso a ella.
Sombreado y reemplazo
No debe confundirse sombrear con reemplazar. Ambos se utilizan cuando una clase derivada hereda de una clase base y ambos vuelven a definir un elemento declarado con otro. No obstante, existen diferencias significativas entre ambos. 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 en la clase derivada, los elementos sombreados se convierten en versiones sobrecargadas de este elemento. Para obtener más información, consulte Sobrecarga de procedimientos.
Tener acceso a un elemento sombreado
Cuando se obtiene acceso a un elemento de una clase derivada, normalmente se logra a través de la instancia actual de dicha clase derivada, mediante la calificación del nombre del elemento con la palabra clave Me. Si una clase derivada ensombrece al elemento de la clase base, puede obtenerse acceso al elemento de la clase base mediante su calificación con la palabra clave MyBase.
Para obtener un ejemplo de tener 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 de crear la variable de objeto también puede afectar al hecho de que la clase derivada tenga acceso a un elemento de sombreado o al elemento sombreado. El ejemplo siguiente crea 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 clase base. La asignación de un objeto dervCls a ella constituye una conversión de ampliación y, por lo tanto, es válida. Sin embargo, la clase base no puede obtener acceso a la versión de sombreado de la variable z en la clase derivada, por lo tanto, el compilador resuelve basObj.z con el valor original de la clase base.
Vea también
Conceptos
Conversiones de ampliación y de restricción