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
解析為原始基底類別值。