當兩個程式設計元素共用相同的名稱時,其中一個元素可以隱藏或 遮蔽另一個。 在這種情況下,被遮蔽的元素無法供參考;相反地,當您的程式代碼使用元素名稱時,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
解析為原始基類值。