Visual Basic におけるシャドウ
2 つのプログラミング要素が同じ名前を共有している場合、それらのうちの 1 つで他方を非表示にしたり、シャドウしたりすることができます。 このような状況では、シャドウされた要素を参照することはできません。代わりに、コードで要素名を使用すると、Visual Basic コンパイラによって、それがシャドウする要素に解決されます。
目的
シャドウの主な目的は、クラス メンバーの定義を保護することです。 基底クラスには、既に定義されているものと同じ名前の要素を作成する変更が含まれる場合があります。 この場合、Shadows
修飾子は、クラスによる参照が、新しい基底クラス要素ではなく定義したメンバーに強制的に解決されるようにします。
シャドウの種類
要素では、2 つの異なる方法で別の要素をシャドウできます。 シャドウする要素は、シャドウされる要素を含む領域のサブ領域内で宣言できます。この場合、シャドウはスコープによって実現されます。 または、派生クラスで、基底クラスのメンバーを再定義できます。この場合、シャドウは継承によって行われます。
スコープによるシャドウ
同じモジュール、クラス、または構造体内のプログラミング要素で、同じ名前で、異なるスコープを持つことができます。 2 つの要素がこのように宣言されていて、コードでそれらが共有する名前を参照する場合、スコープが狭い方の要素によって、他方の要素がシャドウされます (ブロック スコープが最も狭い)。
たとえば、モジュールで temp
という名前の Public
変数を定義でき、モジュール内のプロシージャでも、temp
という名前のローカル変数を宣言できます。 プロシージャ内から temp
への参照ではローカル変数にアクセスしますが、プロシージャの外部から temp
への参照では Public
変数にアクセスします。 この場合、プロシージャ変数 temp
によって、モジュール変数 temp
がシャドウされます。
次の図は、どちらも temp
という名前の 2 つの変数を示します。 ローカル変数 temp
は、それ自身のプロシージャ p
内からアクセスされるときに、メンバー変数 temp
をシャドウします。 ただし、MyClass
キーワードによって、シャドウをバイパスし、メンバー変数にアクセスできます。
スコープによるシャドウの例については、「方法:自分で宣言した変数と同じ名前の変数を隠す」を参照してください。
継承によるシャドウ
派生クラスで、基底クラスから継承されたプログラミング要素を再定義する場合、再定義する要素によって、元の要素がシャドウされます。 任意の型の宣言された要素、またはオーバーロードされた要素のセットを、他の型でシャドウできます。 たとえば、Integer
変数によって、Function
プロシージャをシャドウできます。 別のプロシージャでプロシージャをシャドウする場合、別のパラメーター リストと別の戻り値の型を使用できます。
次の図は、基底クラス b
と、b
から継承する派生クラス d
を示しています。 基底クラスで proc
という名前のプロシージャを定義しており、派生クラスでは、同じ名前の別のプロシージャでそれをシャドウします。 最初の Call
ステートメントで、派生クラスのシャドウする proc
にアクセスしています。 ただし、MyBase
キーワードによって、シャドウをバイパスし、基底クラスのシャドウされたプロシージャにアクセスしています。
継承によるシャドウの例については、「方法:自分で宣言した変数と同じ名前の変数を隠す」と「方法:継承された変数を隠す」を参照してください。
シャドウとアクセス レベル
シャドウする要素には、常に派生クラスを使用して、コードからアクセスできるとは限りません。 たとえば、それが Private
として宣言されているとします。 そのような場合、シャドウが無効化され、コンパイラによって、同じ要素への参照が、シャドウがなかった場合のように解決されます。 この要素は、シャドウするクラスからさかのぼって最も少ない派生ステップでアクセス可能な要素です。 シャドウされた要素がプロシージャの場合は、同じ名前、パラメーター リスト、および戻り値の型を持つ、最も近いアクセス可能なバージョンに解決されます。
次の例に、3 つのクラスの継承階層を示します。 各クラスで 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
のコードからアクセスできます。
シャドウとオーバーライド
シャドウとオーバーライドを混同しないでください。 どちらも派生クラスが基底クラスから継承されるときに使用し、どちらも一方の宣言された要素を他方の要素で再定義します。 しかし、この 2 つには、大きな違いがあります。 比較については、「シャドウとオーバーライドの違い」を参照してください。
シャドウとオーバーロード
派生クラス内で、複数の要素で同じ基底クラス要素をシャドウする場合、シャドウする要素は、その要素のオーバーロードされたバージョンになります。 詳細については、「 Procedure Overloading」を参照してください。
シャドウされた要素へのアクセス
派生クラスから要素にアクセスする場合、通常、その派生クラスの現在のインスタンスから行いますが、要素名を Me
キーワードで修飾します。 派生クラスで基底クラスの要素をシャドウする場合は、MyBase
キーワードで修飾することで、基底クラスの要素にアクセスできます。
シャドウされた要素にアクセスする例については、「方法:派生クラスによって非表示になっている変数にアクセスする」を参照してください。
オブジェクト変数の宣言
オブジェクト変数を作成する方法は、派生クラスがシャドウする要素またはシャドウされた要素にアクセスするかどうかにも影響する場合があります。 次の例では、派生クラスから 2 つのオブジェクトを作成していますが、一方のオブジェクトは基底クラスとして、他方を派生クラスとして宣言しています。
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
が元の基底クラスの値に解決されます。
関連項目
.NET