The Overloads, Overrides, and Shadows Keywords in VB.NET – Part 4

(From an article I wrote in 2004)

Part 4

Note:
This series covers advanced topics and is not intended to be an exhaustive treatment of the subjects discussed. My intention is to provide the reader with a better understanding of the Overloads, Overrides, and Shadows keywords. Where necessary, I will refer the reader to other sources for more details. If you’re a VB.NET programmer who writes software components intended for use by other programmers or applications that can be extended by other programmers, or if you use third party components or extend components written by others, you will certainly want to become more familiar with these keywords as they will allow you to leverage more of the power and flexibility built into an object oriented language like VB.NET.
This series is applicable to VB.NET programmers only. C# provides it’s own flavor of support for member hiding (shadowing), virtual functions, and overloading. And since there are significant differences in the C# implementation, here we’re talking only VB.NET.
Also, in these articles I use the word “method” to mean any procedure in VB.NET (i.e., Subs, Functions, and Property procedures).



So far in this series we discussed Overloading and the Overloads keyword, and Overriding and the Overrides keyword. Each installment in this series builds on the information covered in the previous installment, therefore it’s a good idea to read the previous installments if you have not already done so.

In this installment we’ll end our coverage by discussing member hiding (shadowing) and the Shadows keyword. And while we can’t cover every nuance of shadowing, I’ll provide enough information to give you a strong foundation on the concept so that you can add shadowing to your growing toolbox of programming skills.

The purpose of shadowing (according to MSDN) is to protect a member of a derived class by hiding the implementation of a member in a base class with the same name.

The Shadows keyword is defined in the online help file like this:

The Shadows keyword indicates that a declared programming element shadows, or hides, an identically named element, or set of overloaded elements, in a base class. You can shadow any kind of declared element with any other kind.
A shadowed element is normally unavailable from within the derived class that shadows it. However, the following considerations apply:
· If the shadowing element is not accessible from the code referring to it, for example if it is Private, the reference is resolved to the shadowed element.
· If you shadow an element, you can still access the shadowed element through an object declared with the type of the base class. The 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 keyword forces references through your class to be resolved to your previously defined member, instead of to the new base class element.

Let’s take a closer look at the preceding definition and see if we can get a better understanding of the Shadows keyword.
If you create a method (property, sub, function) in a derived class and you want to be sure that the method is always accessed through a reference to the derived class and never through a reference to the base class (in other words, you don’t want the polymorphism behavior), then you can accomplish this by using the Shadows keyword.

Before I show you what I mean, let me refresh your memory on the Overrides keyword. Remember from our discussion in the previous installment on overriding that you can declare a method in the base class as Overridable and then use the Overrides keyword in a derived class on a method with the same name and signature. Also remember that if you did this and then assigned an object of the derived class to a variable of the base class, you enabled the polymorphism behavior of VB.NET to take place on that method. In that scenario, if the method is accessed through a reference to the base class, and the value stored in that reference is actually an object of the derived class, then the method in the derived class is the one that is executed. Here is an example to help you understand.

Let’s say you have the following two classes and class B is derived from class A and overrides property P in the base class:

Friend Class A
    Public Overridable ReadOnly Property P() As String
        Get
            Return "I'm property P in class A."
        End Get
    End Property
End Class

Friend Class B
    Inherits A
    Public Overrides ReadOnly Property P() As String
        Get
            Return "I'm property P in class B."
        End Get
    End Property
End Class

Having defined your classes in this way, if you run the following code you will see a message box with the message “I’m property P in class A.” This is the expected behavior.

Dim obj As New A
MsgBox(obj.P)

Now if you execute the following code you will see a message box with the message “I’m property P in class B.” This is the behavior caused by the polymorphism mechanism of VB.NET because the true type of the object stored in obj is that of the derived class, even though we declared obj as a reference to the base class.

Dim obj As New A
Dim obj2 As New B 'declare an object of the derived class.
obj = obj2 'assigning an object of the derived class
           'to a variable of the base class.
MsgBox(obj.P)

We learned about this in the previous installment on the Overrides keyword and we mention it again only so we can compare this behavior to that which occurs when we use the Shadows keyword. When we use the Shadows keyword in place of the Overrides keyword as we did in our derived class, the polymorphism mechanism in VB.NET for that member is “turned off.” Change the definition of class B so that it looks like this:

Friend Class B
    Inherits A

    Public Shadows ReadOnly Property P() As String
        Get
            Return "I'm property P in class B."
        End Get
    End Property
End Class

Now execute those two pieces of code and each time you do you will always get the same result, a message box with the message “I’m property P in class A.” This happens because the Shadows keyword forces the reference to be resolved to the class that was used when declaring the variable, and it no longer matters what the true type of the object stored in that variable is, it matters only that it was declared as a variable of class A. If you wanted to access property P in the derived class, you would have to do it through a reference to the derived class.

Now you may be wondering: Of what use is this anyway?
The main reason is that you get to decide whether you want the polymorphism mechanism to be “on or off” for a particular method, depending on the specific needs of your design. And you can avoid conflicts with your code when the definition of a base class is changed. This is what is meant when it says in the definition that the Shadows keyword’s purpose is to protect the members in a derived class.
This means that by using the Shadows keyword a member in a derived class can be accessed only through a reference to an object of the derived class, and a member in the base class can be accessed only through a reference to an object of the base class.

Here are a couple of more reasons why understanding the Shadows keyword as I just described comes in very handy. First remember that if you are in a situation where you could have chosen between the Shadows keyword and some other keyword (such as the Overrides or Overloads keywords), and you don’t use any of them, the compiler defaults to the Shadows keyword. So even if you don’t use any of them, the behavior will be as if you had used the Shadows keyword (you will also get a warning from the compiler under it’s default configuration but the code will compile). This default behavior in the compiler was a wise decision because it means novice programmers who are not yet experienced enough to know whether they should use the Shadows, Overrides, or Overloads keywords, can just decide not to use any of them and the compiler defaults to the Shadows keyword as the safest option.

Now imagine you are using a component from a vendor and you don’t have access to the component’s source files, and you create a derived class from a base class contained in that component. Imagine in your derived class you added a function called FunctionA. If, at some later date, the vendor ships a new version of his component to you and now it also contains a function called FunctionA (or it contains a variable named FunctionA – sounds weird, but it’s possible), you wouldn’t have to worry about your function being adversely affected. If the Shadows keyword was not the default keyword and shadowing was not in effect, your code would not execute as expected, or it would not execute at all. Since shadowing is the default, you can leave it alone to implicitly use shadowing. Or you can use the Shadows keyword to explicitly indicate you are shadowing the function.
Remember, not selecting one of the keywords in that scenario is the same as if you are selecting the Shadows keyword.

Another thing to keep in mind is if the language specification changes in future versions of VB.NET and the Shadows keyword is no longer the default (unlikely – but who knows), by understanding how the Shadows keyword works you will understand what you need to do to modify and update your source code.

And finally, you should know that shadowing will not work as expected if you declare your member as private in the derived class so that it cannot be accessed from outside it’s class, and the member you are shadowing is declared public (or with another modifier which allows access) in the base class. In that scenario a reference to the member in the derived class will resolve to the base class as if the member in the derived class was not there.

Here’s an example. If you create two classes like this:

Public Class MyBaseClass
    Public strMyStringVariable As String = _
                           "Base class string"
End Class

Public Class MyDerivedClass : Inherits MyBaseClass
    Public Shadows strMyStringVariable As String = _
                                   "Derived class string"
End Class

Then execute this code:

Dim b As New MyBaseClass
MsgBox(b.strMyStringVariable)
Dim d As New MyDerivedClass
MsgBox(d.strMyStringVariable)

You will see two message boxes. The first will display the text “Base class string” and the second will display the text “Derived class string.” This is the expected behavior according to the definition of the Shadows keyword. Now, if you change the definition of the derived class so that it looks like this:

Public Class MyDerivedClass : Inherits MyBaseClass
    Private Shadows strMyStringVariable As String = _
                             "Derived class string"
End Class

Execute the same code as before and both message boxes will display the text “Base class string.” This happens because the Private keyword is used in the declaration of the variable in the derived class. Since making the variable private removes the derived class variable from the same scope as the base class variable, the Shadows keyword is ignored in this scenario.

Shadowing does not apply only to the methods of a class

You may have noticed we’ve been using the Shadows keyword on properties and also on variables. As a matter of fact, the Shadows keyword can be used in the declaration of any of the following elements:

  1. Class Statement
  2. Const Statement
  3. Declare Statement
  4. Delegate Statement
  5. Dim Statement
  6. Enum Statement
  7. Event Statement
  8. Function Statement
  9. Interface Statement
  10. Property Statement
  11. Structure Statement
  12. Sub Statement

In fact, you can also mix them up and shadow one type of programming element with a completely different kind of programming element. In the following example we show how to shadow a function in a base class with a variable in a derived class.

Create two classes with the following definition:

Public Class MyBaseClass
    Public Function MyStringVariable() As String
        Return "Function in the base class is called"
    End Function
End Class

Public Class MyDerivedClass : Inherits MyBaseClass
    Public Shadows MyStringVariable As String = _
      "Derived class string in a variable"
End Class

Execute this code:

Dim b As New MyBaseClass
MsgBox(b.MyStringVariable)
Dim d As New MyDerivedClass
MsgBox(d.MyStringVariable)

You will see two message boxes displaying first this message: “Function in the base class is called” and then this message: “Derived class string in a variable.”

This demonstrates how it is possible to shadow one kind of programming element with another kind of programming element. And it makes sense if you remember that the purpose of the Shadows keyword is to protect the members of a derived class, because without shadowing, the program in this scenario would not compile. However, it does compile even without using the Shadows keyword because shadowing is the default that is assumed by the compiler. By now it must make sense to you why the Shadows keyword was made the default by the makers of the compiler (in this case, Microsoft).

The NotOverridable keyword

Although the NotOverridable keyword applies to inheritance and polymorphism and is used in conjunction with the Overrides keyword, it’s function has strong similarities to the Shadows keyword and is worth mentioning here.

Shadowing breaks an inheritance chain as we described earlier when discussing how the Shadows keyword can “turn off” the polymorphism mechanism of VB.NET. This means if class B inherits from class A and a method in class B Shadows an Overridable method in class A, and you create a class C that inherits from class B, you cannot override the method in class C because you shadowed it in class B. If that sounds confusing, then try it out to see what I mean.

Similar to the Shadows keyword, the NotOverridable keyword also breaks an inheritance chain, but it works a little differently than the Shadows keyword. Remember that the main purpose of the Shadows keyword is to protect the members of a derived class. The Shadows keyword forces a method in the derived class to be accessed only directly through a reference to the derived class and a method in the base class to be referenced only directly through a reference to the base class. The effect of the Shadows keyword is immediately apparent in the class where it is used.

The NotOverridable keyword is used in a derived class when you are overriding a method and you don’t want anyone who uses your derived class as their base class to be able to continue to override that same method. The effect of the NotOverridable keyword is apparent only when someone tries to create a derived class from your class and then tries to override the method which you declared with the NotOverridable keyword. Remember: The NotOverridable keyword breaks the inheritance chain, but unlike when using the Shadows keyword, it does not become apparent until a derived class is created from your class.

Another thing to note is that the NotOverridable keyword can only be used in a declaration where the Overrides keyword is also being used. That may seem confusing but consider its use. To make a method overridable you must use the Overrides keyword or the MustOverride keyword (explained previously in part 3 of this series). From that point forward, if you declare the same method in your derived classes without the Overrides keyword, the compiler will warn you and assume you are shadowing the method. If you shadow a method then you don’t need to make it NotOverridable and the compiler won’t let you do it. So, if it is not your intent to shadow the method, you must use the Overrides keyword so the compiler knows you are not shadowing the method. And if you want to make that method NotOverridable, you must declare it with that keyword as well. So you have to override it to declare it NotOverridable.
Sound confusing? Try it to see what I mean.

More about shadowing, overloading, and overriding

You cannot use the Shadows keyword in the declaration of a method if you are also using either the Overrides or Overloads keywords in the same declaration. However, you can combine both the Overrides and the Overloads keywords together in the same declaration of a method. Just remember from the previous installments in this series of articles how and why each keyword is used.

Shadowing, similar to Overloads, allows you to define a method that has the same name as another method in a base class, but without having to ensure a different signature. You can also shadow a method that is defined in the same class using the Shadows keyword and a different signature, however this has the similar effect of overloading a method and can be used when your intent is to overload and protect your methods at the same time. And since the Shadows keyword is the default, declaring multiple methods with the same name and different signatures without using either keyword is enough to ensure they are both overloaded and shadowed (I never said this was simple!).

Another important point to consider is that when you shadow overloaded methods of the base class in a derived class, the user of your derived class will not be able to access the overloaded methods of the base class through an object variable of your class.
This means that if there are four overloaded methods with the same name in the base class, and you want to shadow one of them in a derived class, you will be shadowing all of them, and none of those in the base class are accessible through your derived class. That’s because shadowing is based on the name of the member and does not concern itself with any other differences such as signature, parameters, etc.

Summary

In this series we discussed the Overloads, Overrides, and Shadows keywords. We looked at the basics of how, when, and why each is used and if you followed along you are well on your way to a thorough understanding of these related concepts and keywords. At first they can be confusing, but as you use them in your code and see how they affect your programs you’ll begin to get a feel for how they work.

When you design your own classes keep these concepts in mind and decide whether you will need to make use of them. After reading these articles and the information in the links I’ve provided, you should feel comfortable in using these keywords and in your knowledge of how they affect the design of a program.

To recap the basic use for those keywords:

  • The Overloads keyword (discussed in part 2 of this series) can be used when you have a method that performs the same action and you need it to perform that action on a different number of parameters or different data types, while continuing to use the same name for the method.
  • The Overrides keyword (along with it’s related keywords) is used to implement inheritance based polymorphism (discussed in part 3 of this series).
  • The Shadows keyword is used to protect the members of a derived class from changes made to the base class and it is assumed as the default by the compiler in cases where it could be used but is not explicitly indicated.

Another technique you can use to help you further understand these keywords is to actually create test classes and then run the code to see the different behavior of your application. This is a great technique for achieving a deeper understanding of various programming elements and keywords, and it’s one I use often.

This concludes this series on the Overloads, Overrides, and Shadows keywords. I hope you had as much fun reading these articles as I had writing them!

For a more thorough understanding of these and other related concepts, familiarize yourself with the MSDN web site and keep abreast of the articles you find there. MSDN is the best source of information for VB.NET language elements, and if there are any language changes that affect these keywords in future versions of VB, that’s where you’ll here about them first.

VN:F [1.9.3_1094]
Rate this content:
Rating: 3.7/5 (3 votes cast)
The Overloads, Overrides, and Shadows Keywords in VB.NET - Part 4, 3.7 out of 5 based on 3 ratings No Comments yet.
Leave a Comment