Visual Basic 中的遮蔽功能

當兩個程式設計元素共用相同的名稱時,其中一個元素可能會隱藏或「遮蔽」另一個元素。 在這種情況下,受遮蔽的元素無法用於參考;相反地,當程式碼使用該元素名稱時,Visual Basic 編譯器會將其解析為遮蔽的元素。

目的

遮蔽的主要用途是保護類別成員的定義。 基底類別可能會進行變更,此變更會建立與您已定義元素相同的名稱。 如果發生這種情況,Shadows 修飾元會強制透過類別參考來解析為您所定義的成員,而不是新的基底類別元素。

遮蔽類型

元素可以透過兩種不同的方式遮蔽另一個元素。 遮蔽元素可以在包含受遮蔽元素之區域的子區域內宣告,在此情況下,遮蔽是「透過範圍」完成。 或者,衍生類別可以重新定義基底類別的成員,在此情況下,遮蔽是「透過繼承」完成。

透過範圍遮蔽

同一個模組、類別或結構中的程式設計元素可以具有相同名稱,但範圍不同。 以這種方式宣告兩個元素,而程式碼會參考它們共用的名稱時,具有較窄範圍的元素會遮蔽另一個元素 (區塊範圍為最窄)。

例如,模組可以定義名為 tempPublic 變數,而模組內的程序可以宣告同樣名為 temp 的區域變數。 程序內 temp 的參考會存取區域變數,而程序外 temp 的參考則存取 Public 變數。 在此情況下,程序變數 temp 會遮蔽模組變數 temp

下圖顯示兩個變數,雙方都名為 temp。 區域變數 temp 從自己的程序 p 內存取時,會遮蔽成員變數 temp。 不過,MyClass 關鍵字會略過遮蔽並存取成員變數。

Graphic that shows shadowing through scope.

如需透過範圍遮蔽的範例,請參閱操作說明:隱藏與您變數同名的變數

透過繼承遮蔽

如果衍生類別重新定義繼承自基底類別的程式設計元素,則重新定義元素會遮蔽原始元素。 您可以使用任何其他類型來遮蔽任何已宣告元素或一組多載元素的類型。 例如,Integer 變數可以遮蔽 Function 程序。 如果您使用另一個程序來遮蔽程序,則可以使用不同參數清單和不同的傳回型別。

下圖顯示基底類別 b,以及繼承自 b 的衍生類別 d。 基底類別會定義名為 proc 的程序,而衍生類別會以同名的另一個程序遮蔽它。 第一個 Call 陳述式會存取衍生類別中的遮蔽 proc。 不過,MyBase 關鍵字會略過遮蔽,並存取基底類別中的受遮蔽程序。

Graphic diagram of shadowing through inheritance

如需透過繼承遮蔽的範例,請參閱操作說明:隱藏與您變數同名的變數操作說明:隱藏繼承的變數

遮蔽和存取層級

使用衍生類別的程式碼不一定可以存取遮蔽的元素。 例如,它可能會宣告為 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。 當模組 callDisplaysecondClass 內呼叫 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 解析為原始基底類別值。

另請參閱