Shadowing in Visual Basic

When two programming elements share the same name, one of them can hide, or shadow, the other one. In such a situation, the shadowed element is not available for reference; instead, when your code uses the element name, the Visual Basic compiler resolves it to the shadowing element.

Purpose

The main purpose of shadowing is to protect the definition of your class members. The base class might undergo a change that creates an element with the same name as one you have already defined. If this happens, the Shadows modifier forces references through your class to be resolved to the member you defined, instead of to the new base class element.

Types of Shadowing

An element can shadow another element in two different ways. The shadowing element can be declared inside a subregion of the region containing the shadowed element, in which case the shadowing is accomplished through scope. Or a deriving class can redefine a member of a base class, in which case the shadowing is done through inheritance.

Shadowing Through Scope

It is possible for programming elements in the same module, class, or structure to have the same name but different scope. When two elements are declared in this manner and the code refers to the name they share, the element with the narrower scope shadows the other element (block scope is the narrowest).

For example, a module can define a Public variable named temp, and a procedure within the module can declare a local variable also named temp. References to temp from within the procedure access the local variable, while references to temp from outside the procedure access the Public variable. In this case, the procedure variable temp shadows the module variable temp.

The following illustration shows two variables, both named temp. The local variable temp shadows the member variable temp when accessed from within its own procedure p. However, the MyClass keyword bypasses the shadowing and accesses the member variable.

Graphic that shows shadowing through scope.

For an example of shadowing through scope, see How to: Hide a Variable with the Same Name as Your Variable.

Shadowing Through Inheritance

If a derived class redefines a programming element inherited from a base class, the redefining element shadows the original element. You can shadow any type of declared element, or set of overloaded elements, with any other type. For example, an Integer variable can shadow a Function procedure. If you shadow a procedure with another procedure, you can use a different parameter list and a different return type.

The following illustration shows a base class b and a derived class d that inherits from b. The base class defines a procedure named proc, and the derived class shadows it with another procedure of the same name. The first Call statement accesses the shadowing proc in the derived class. However, the MyBase keyword bypasses the shadowing and accesses the shadowed procedure in the base class.

Graphic diagram of shadowing through inheritance

For an example of shadowing through inheritance, see How to: Hide a Variable with the Same Name as Your Variable and How to: Hide an Inherited Variable.

Shadowing and Access Level

The shadowing element is not always accessible from the code using the derived class. For example, it might be declared Private. In such a case, shadowing is defeated and the compiler resolves any reference to the same element it would have if there had been no shadowing. This element is the accessible element the fewest derivational steps backward from the shadowing class. If the shadowed element is a procedure, the resolution is to the closest accessible version with the same name, parameter list, and return type.

The following example shows an inheritance hierarchy of three classes. Each class defines a Sub procedure display, and each derived class shadows the display procedure in its base class.

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  

In the preceding example, the derived class secondClass shadows display with a Private procedure. When module callDisplay calls display in secondClass, the calling code is outside secondClass and therefore cannot access the private display procedure. Shadowing is defeated, and the compiler resolves the reference to the base class display procedure.

However, the further derived class thirdClass declares display as Public, so the code in callDisplay can access it.

Shadowing and Overriding

Do not confuse shadowing with overriding. Both are used when a derived class inherits from a base class, and both redefine one declared element with another. But there are significant differences between the two. For a comparison, see Differences Between Shadowing and Overriding.

Shadowing and Overloading

If you shadow the same base class element with more than one element in your derived class, the shadowing elements become overloaded versions of that element. For more information, see Procedure Overloading.

Accessing a Shadowed Element

When you access an element from a derived class, you normally do so through the current instance of that derived class, by qualifying the element name with the Me keyword. If your derived class shadows the element in the base class, you can access the base class element by qualifying it with the MyBase keyword.

For an example of accessing a shadowed element, see How to: Access a Variable Hidden by a Derived Class.

Declaration of the Object Variable

How you create the object variable can also affect whether the derived class accesses a shadowing element or the shadowed element. The following example creates two objects from a derived class, but one object is declared as the base class and the other as the derived class.

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  

In the preceding example, the variable basObj is declared as the base class. Assigning a dervCls object to it constitutes a widening conversion and is therefore valid. However, the base class cannot access the shadowing version of the variable z in the derived class, so the compiler resolves basObj.z to the original base class value.

See also