2 つのプログラミング要素が同じ名前を共有している場合、そのうちの 1 つは、もう 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
内のコードはそれにアクセスできます。
シャドウとオーバーライド
シャドウとオーバーライドを混同しないでください。 どちらも、派生クラスが基底クラスから継承する場合に使用され、宣言された 1 つの要素を別の要素と再定義します。 しかし、この 2 つの間には大きな違いがあります。 比較については、「 シャドウとオーバーライドの違い」を参照してください。
シャドウとオーバーロード
派生クラス内の複数の要素を持つ同じ基底クラス要素をシャドウすると、シャドウ要素はその要素のオーバーロードされたバージョンになります。 詳細については、「 プロシージャのオーバーロード」を参照してください。
Shadowed 要素へのアクセス
派生クラスから要素にアクセスする場合は、通常、その派生クラスの現在のインスタンスを通じて、要素名を Me
キーワードで修飾します。 派生クラスが基底クラスの要素をシャドウする場合は、 MyBase
キーワードで修飾することで基底クラス要素にアクセスできます。
シャドウされた要素にアクセスする例については、「 方法: 派生クラスによって非表示の変数にアクセスする」を参照してください。
オブジェクト変数の宣言
オブジェクト変数を作成する方法は、派生クラスがシャドウ要素にアクセスするか、シャドウされた要素にアクセスするかにも影響します。 次の例では、派生クラスから 2 つのオブジェクトを作成しますが、1 つのオブジェクトは基底クラスとして、もう 1 つは派生クラスとして宣言されています。
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