当两个编程元素共享同名时,其中一个元素可以隐藏或 隐藏另一个元素。 在这种情况下,阴影元素不可用供参考;相反,当代码使用元素名称时,Visual Basic 编译器会将其解析为阴影元素。
目的
阴影的主要目的是保护类成员的定义。 基类可能会发生更改,该更改创建与已定义的元素同名的元素。 如果发生这种情况,Shadows
修饰符会强制将通过你的类的引用解析为你定义的成员,而不是新的基类元素。
阴影类型
元素可以通过两种不同的方式隐藏另一个元素。 可以在包含阴影化元素的区域的子区域内声明阴影元素,在这种情况下,阴影处理是通过范围实现的。 或者派生类可以重新定义基类的成员,在这种情况下,阴影 是通过继承完成的。
通过范围实现阴影
同一模块、类或结构中的元素可以具有相同的名称,但范围不同。 以这种方式声明两个元素并且代码引用它们共享的名称时,具有较窄范围的元素将隐藏另一个元素(块范围为最窄)。
例如,模块可以定义一Public
个名为temp
的变量,模块中的过程可以声明一个局部变量也命名temp
。
temp
从过程内部引用访问局部变量,同时从过程外部引用temp
访问变量Public
。 在这种情况下,过程变量 temp
将隐藏模块变量 temp
。
下图显示了两个变量,两个变量都命名 temp
。 从其自身过程temp
中访问时,局部变量temp
会遮蔽成员变量p
。 但是,关键字 MyClass
会绕过阴影并访问成员变量。
有关通过范围实现阴影的示例,请参阅如何:隐藏与你的变量同名的变量。
通过继承实现阴影。
如果派生类重新定义从基类继承的编程元素,则重新定义元素将隐藏原始元素。 可以用任何其他类型对任何类型的已声明元素或重载元素集进行阴影处理。 例如,变量 Integer
可以隐藏过程 Function
。 如果使用另一个过程隐藏过程,则可以使用不同的参数列表和不同的返回类型。
下图显示了一个基类b
和一个从d
中继承的派生类b
。 基类定义了一个名为 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
通过 display
过程对 Private
进行阴影处理。 当模块 callDisplay
在 display
中调用 secondClass
时,调用代码位于 secondClass
外部,因此无法访问私有 display
过程。 阴影已失效,编译器将引用解析为基类 display
过程。
但是,进一步派生的类 thirdClass
声明 display
为 Public
,因此代码在 callDisplay
中可以访问它。
阴影和重写。
不要将阴影与重写混淆。 当派生类继承自基类时,这两者都用于重新定义一个声明的元素和另一个元素。 但两者之间存在重大差异。 有关比较,请参阅阴影和重写之间的差异。
阴影和重载
如果在派生类中对具有多个元素的同一个基类元素进行阴影处理,则阴影元素将成为该元素的重载版本。 有关详细信息,请参阅 过程重载。
访问阴影元素
访问派生类的元素时,通常通过该派生类的当前实例,并使用 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
为原始基类值。