Visual Basic 中的隐藏
当两个编程元素共享相同的名称时,其中一个可以隐藏或阴影化另一个。 在这种情况下,阴影化的元素不可用于引用;相反,当代码使用元素名称时,Visual Basic 编译器会将其解析为阴影元素。
目的
阴影的主要目的是保护类成员的定义。 基类可能会发生更改,该更改将创建一个与你已定义的元素同名的元素。 如果发生这种情况,Shadows
修饰符会强制将通过你的类的引用解析为你定义的成员,而不是新的基类元素。
阴影类型
一个元素可以通过两种不同的方式对另一个元素进行阴影处理。 可以在包含阴影化元素的区域的子区域内声明阴影元素,在这种情况下,阴影处理是通过范围实现的。 或者,派生类可以重新定义基类的成员,在这种情况下,阴影处理是通过继承完成的。
通过范围实现阴影
同一模块、类或结构中的编程元素可以具有相同的名称,但范围不同。 如果以这种方式声明两个元素,并且代码引用了它们共享的名称,则范围较窄的元素将对另一个元素进行阴影处理(块范围是最窄的范围)。
例如,模块可以定义一个名为 temp
的 Public
变量,并且该模块中的一个过程可以声明同样名为 temp
的局部变量。 在该过程中引用 temp
将访问局部变量,而从该过程外部引用 temp
将访问 Public
变量。 在这种情况下,过程变量 temp
对模块变量 temp
进行了阴影处理。
下图显示了两个名为 temp
的变量。 局部变量 temp
在从其自己的过程 p
中被访问时对成员变量 temp
进行阴影处理。 不过,MyClass
关键字将绕过阴影并访问该成员变量。
有关通过范围实现阴影的示例,请参阅如何:隐藏与你的变量同名的变量。
通过继承实现阴影。
如果派生类重新定义了从基类继承的编程元素,则重新定义的元素将对原始元素进行阴影处理。 可以用任何其他类型对任何类型的已声明元素或重载元素集进行阴影处理。 例如,Integer
变量可以对 Function
过程进行阴影处理。 如果使用另一个过程来对一个过程进行阴影处理,可以使用不同的参数列表和不同的返回类型。
下图显示了基类 b
以及继承自 b
的派生类 d
。 基类定义了一个名为 proc
的过程,派生类将使用另一个同名的过程来对该过程进行阴影处理。 第一条 Call
语句将访问派生类中的阴影 proc
。 不过,MyBase
关键字将绕过阴影并访问基类中的阴影化过程。
有关通过继承实现阴影的示例,请参阅如何:隐藏与你的变量同名的变量以及如何:隐藏继承的变量。
阴影和访问级别
不能始终使用派生类从代码访问阴影元素。 例如,它可能声明为 Private
。 在这种情况下,阴影会失效,并且如果没有阴影,编译器将解析对它所有的同一元素的任何引用。 此元素是可访问的元素,通过从阴影类向后执行最少的派生步骤即可访问。 如果阴影化元素是一个过程,则将解析为具有相同名称、参数列表和返回类型的最接近的可访问版本。
下面的示例显示了三个类的继承层次结构。 每个类都定义一个 Sub
过程 display
,并且每个派生类都会在其基类中对 display
过程进行阴影处理。
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
在前面的示例中,派生类 secondClass
通过 Private
过程对 display
进行阴影处理。 当模块 callDisplay
在 secondClass
中调用 display
时,调用代码位于 secondClass
外部,因此,无法访问私有 display
过程。 阴影已失效,编译器将引用解析为基类 display
过程。
但是,进一步派生的类 thirdClass
将 display
声明为 Public
,因此 callDisplay
中的代码可以访问它。
阴影和重写。
不要将阴影与重写混淆。 当派生类从基类继承时会使用这两种方法,并且它们都将一个已声明的元素重新定义为另一个。 但两者之间存在显著差异。 有关比较,请参阅阴影和重写之间的差异。
阴影和重载
如果在派生类中对具有多个元素的同一个基类元素进行阴影处理,则阴影元素将成为该元素的重载版本。 有关更多信息,请参见 Procedure Overloading。
访问阴影化元素
从派生类访问某个元素时,通常通过该派生类的当前实例来执行此操作,方法是使用 Me
关键字限定元素名称。 如果派生类对基类中的元素进行阴影处理,则可以通过使用 MyBase
关键字限定基类元素来访问它。
有关访问阴影化元素的示例,请参阅如何:访问被派生类隐藏的变量。
对象变量的声明
创建对象变量的方式还会影响派生类是访问阴影元素还是访问阴影化元素。 下面的示例从派生类创建两个对象,但一个对象声明为基类,另一个对象声明为派生类。
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
在前面的示例中,变量 basObj
声明为基类。 为它分配一个 dervCls
对象将形成扩大转换,因此,这是有效的。 但是,基类无法访问派生类中的变量 z
的阴影版本,因此编译器将 basObj.z
解析为原始基类值。