Home > Articles > Business & Management > Finance & Investing

  • Print
  • + Share This
This chapter is from the book

Replacing Methods in a Derived Class

Now that you have seen the high-level motivation for polymorphism, it's time for a low-level explanation of the mechanics of how members are accessed at runtime. To use inheritance to add polymorphic behavior to your designs, you must first understand the differences between static binding and dynamic binding.

Static binding and dynamic binding represent two different ways in which a client can invoke a method or property of an object. Static binding is usually more straightforward and results in better performance. Dynamic binding yields greater flexibility and is the underlying mechanism that allows a derived class to replace behavior inherited from a base class. The latter type of binding is one of the crucial ingredients of polymorphic programming.

Static Binding

Listing 5.3 A simple base class with a statically bound method

Public Class Human
  Public Function Speak() As String
    Return "I am a human"
  End Function
End Class

Public Class Programmer : Inherits Human
  '*** inherits Speak from base class
End Class

First, let's tackle static binding. Suppose you are designing the Human and Programmer classes and come up with the two class definitions shown in Listing 5.3. Now imagine someone writes code that creates a Programmer object and invokes the Speak method. The caller can invoke the Speak method through a reference variable of type Programmer or through a reference variable of type Human:

Dim programmer1 As Programmer = New Programmer()
Dim human1 As Human

Dim message1, message2 As String
message1 = programmer1.Speak()  '*** calls Human.Speak()
message2 = human1.Speak()       '*** calls Human.Speak()

Console.WriteLine(message1)     '*** "I am a human"
Console.WriteLine(message2)     '*** "I am a human"

Both method invocations work via static binding, which is the default method invocation mechanism used by Visual Basic .NET and by the CLR. Static binding is based on the type of the reference variable, not the type of object being referenced. For example, if you are accessing a Programmer object through a reference variable of type Human, the type information from the definition of Human is used to bind the client to the correct member definition.

Another important aspect of static binding is that the decision about where to locate the definition for the method being invoked is always made at compile time—that is, statically. This decision-making process is different than in dynamic binding, in which the decision about where to locate the method definition is made at runtime. With static binding, the compiler can perform more of the work at compile time. For this reason, static binding can provide a measurable performance advantage over dynamic binding.

Dynamic Binding and Overridable Methods

One of the most valuable features of inheritance is the fact that the designer of a base class can provide default behavior that can optionally be replaced by a derived class author. For example, a base class author can provide a default implementation for a method. A derived class author can then choose whether to use the base class implementation or to write a more specialized implementation. In some cases, a derived class author even has the option of extending the base class implementation by adding extra code to the derived class.

Using a derived class to replace the implementation of a method or a property defined in a base class is known as overriding. Method overriding relies on dynamic binding, not static binding. Dynamic binding takes into account the type of an object at runtime, which gives the CLR a chance to locate and call the overriding method. In this way dynamic binding supports more flexible code, albeit with a runtime cost. Interestingly, dynamic binding is the default in the Java programming language and, in fact, the only option in Java in most cases.

An example will illustrate why dynamic binding is so important. Imagine you have written the following client-side code that uses the programming contract defined by the Human class shown in Listing 5.3:

Public Class Reporter
  Public Sub InterviewHuman(ByVal target As Human)
    Dim Message As String = target.Speak()
    MessageBox.Show(Message)
  End Sub
End Class

A caller could invoke the InterviewHuman method by passing a Human object or by passing a Programmer object. Whichever type of object is passed to the InterviewHuman method must, however, provide an implementation of the Speak method as defined by the programming contract of the Human class.

An important aspect of polymorphism is that any Human-derived class should be able to provide a behavior for the Speak method that differs from the behavior of other Human-derived classes. For example, a Programmer class should be able to provide an implementation of Speak that is different from that in the Human class. You cannot take advantage of these different behaviors if static binding is being used. Because the InterviewHuman method programs against the Human type, static binding would result in every call to Speak being dispatched to the implementation defined in the Human class. Therefore, true polymorphic behavior is not possible with static binding. Your class design must contain methods that are invoked through dynamic binding.

Of course, the features of dynamic binding don't apply to all kinds of class members. When you add methods and properties to a base class, you have the option of defining them to be invoked through either static binding or dynamic binding. You don't have the same option when you add fields to a base class. In the CTS, fields can be accessed only through static binding. In other words, method and properties can be declared as overridable but fields cannot. This restriction gives public methods and properties yet another advantage over public fields from a design perspective.

Now that you've learned the fundamental concepts behind dynamic binding, it's time to see the Visual Basic .NET syntax that's required to support it. You enable dynamic binding by defining overridable methods and properties.

Listing 5.4 A simple base class with a dynamically bound method

Public Class Human
  Public Overridable Function Speak() As String
    '*** default implementation
    Return "I am a human"
  End Function
End Class

The first requirement to enable overriding is that a base class must define the method or property as overridable. To do so, you declare the member definition using the Overridable keyword (equivalent to the virtual keyword in C# and C++), as shown in Listing 5.4. It's important to understand the implications of defining a method with the Overridable keyword. In this case, it means that every invocation of the Speak method through a reference variable of type Human will result in dynamic binding. Also, classes that inherit from Human will have the option of overriding the Speak method to provide a more specialized implementation.

Because a dynamically bound call is potentially slower than a statically bound call, it makes sense that a base class author must ask for it explicitly. Languages such as Visual Basic .NET and C# require a base class author to be very explicit about declaring methods that are overridable for another reason, too: When a method is overridable, the design becomes more challenging because the method overriding complicates the contract between a base class and its derived classes. We will revisit this topic later in this chapter. For now, just take it on faith that declaring a method or property as overridable increases your responsibilities as a base class author.

Let's finish our example by creating a derived class that overrides a method implementation defined within its base class. First, the derived class must contain a method with the same name and the same signature as the overridable method in its base class. Second, the overriding method must be explicitly declared to override the base class implementation using the Overrides keyword. In the following code fragment, the Programmer class overrides the Speak method inherited from the Human class of Listing 5.4:

Public Class Programmer : Inherits Human
  Public Overrides Function Speak() As String
    '*** overriding implementation
    Return "I am a programmer"
  End Function
End Class

Now that we've written a derived class definition that overrides a method implementation in its base class, we are ready to see an example of dynamic binding in action. Examine the following client-side code:

Dim programmer1 As Programmer = New Programmer()
Dim human1 As Human = programmer1
Dim message1, message2 As String

message1 = programmer1.Speak()  '*** calls Programmer.Speak
message2 = human1.Speak()       '*** calls Programmer.Speak

Console.WriteLine(message1)     '*** "I am a programmer"
Console.WriteLine(message2)     '*** "I am a programmer"

As this code demonstrates, it doesn't matter whether you access the Programmer object through a reference variable of type Programmer or of type Human. The dynamic binding scheme employed by the CLR always locates the appropriate method implementation by looking up the inheritance hierarchy for the most-derived class that holds a definition for the method in question. In the preceding code, Programmer is the most-derived class that contains an implementation of the Speak method.

Chaining Calls from a Derived Class to a Base Class

When you override a method, it's fairly common practice to chain a call from your overriding implementation in the derived class to the overridden implementation in the base class. This technique allows you to leverage the implementation provided by the base class and extend it with extra code written in the derived class. Consider the following reimplementation of the Programmer class:

Public Class Programmer : Inherits Human
  Public Overrides Function Speak() As String
    '*** chain call to Speak method in base class
    Return MyBase.Speak() & " who is a programmer"
  End Function
End Class

The Visual Basic .NET keyword MyBase is used in a derived class to explicitly access public or protected members in its base class. In this example, the Programmer definition of Speak makes an explicit call to the Human implementation of Speak. This approach allows the derived class author to reuse and extend the method implementation provided by the base class author.

As shown in the preceding example, the MyBase keyword allows a derived class author to chain a call to the base class author's implementation. A chained call doesn't have to be made at the beginning of the derived class implementation, however. It can be made at any point in the overriding implementation.

Design Issues with Overridable Methods

You've just seen the syntax for creating overridable methods. You've also seen the syntax for overriding a method and for chaining a call to an overridden base class implementation. As a result of the discussion, you might have concluded that the syntax required for method overriding isn't especially complicated.

In reality, mastering the syntax is the easy part. Making sure you get the semantics correct is a much tougher job. Anyone who has managed a large software project using inheritance and method overriding can tell you that managing the semantics of overridable methods and properties requires a high level of expertise and attention to detail.

An overridable method complicates the programming contract of a base class because a derived class author can use any of three possible approaches:

  • A derived class author can inherit a base class implementation and reuse it without modification.

  • A derived class author can provide an overriding implementation that chains a call back to the base class implementation.

  • A derived class author can provide an overriding implementation that does not chain a call back to the base class implementation.

Consider these three approaches for dealing with an overridable method from a design perspective. You might say that there are really three options: reusing, extending, and replacing. When a derived class inherits a method, it reuses the base class implementation. When a derived class overrides a method and chains a call back the base class, it extends the base class implementation. When a derived class overrides a method and does not chain a call back the base class, it replaces the base class implementation.

While the CLR's support for method overriding allows for reusing, extending, and replacing, many overridable methods have semantics that do not support all three approaches. The overridable Finalize method of the Object class, for instance, is a real-world example of an overridable method that does not allow replacing. If you elect to override the Finalize method in a user-defined class, your implementation must chain a call back to the Finalize implementation of the base class. If you fail to chain a call to the base class implementation, you have broken the semantic contract of this overridable method and your code will likely exhibit problematic behavior. Chapter 10 discusses when and how to override the Finalize method; for now, just recognize that replacing the implementation for an overridable method creates problems.

As you can see, some overridable methods only support reusing or extending the base class implementation. An overridable method may also have semantics that allow for reusing and replacing yet disallow extending. In general, the semantics of overridable methods and properties require extra attention.

The semantics involved with chaining can become even more complicated because the semantics of some overridable methods require an overriding implementation to chain a call back to the base class implementation at a specific point in time. For example, the semantics of one overridable method might require overriding method implementations to chain a call to the base class implementation before doing any work in the derived class. The semantics of another overridable method might require overriding method implementations to chain a call to the base class implementation after all work has been completed in the derived class implementation.

This discussion should lead you to two important observations:

  • The semantics of method and property overriding are often sensitive to whether an overriding method should chain a call to its base class.

  • The semantics of overriding can be affected by whether the chained call should be made at the beginning or at the end of the overriding method or property implementation.

If you must ever design a base class, it is your responsibility to document the semantics for each overridable method and property. Your documentation should specify for each overridable method and property whether chaining a call back to your base class implementation is required. You should also point out any occasion where a chained call must be made at the beginning or at the end of the overriding implementation in the derived class.

Even if you never design or write a base class definition, you must keep these rules in mind. As a .NET programmer, you will almost certainly encounter situations in which you must create classes that inherit from one of the base classes provided by the .NET Framework.

When you are working with inheritance, semantic errors can be much more challenging to find than syntax errors. The compiler will catch syntax errors and identify their exact locations in your code, but it cannot catch semantic errors. This factor makes semantic errors related to inheritance far more difficult to locate. Making sure the semantics for overridable methods are well defined and adhered to requires a lot of discipline. It may also require coordination across different development teams.

Declaring a Method as NotOverridable

Recall that a class created with Visual Basic .NET is inheritable by default. If you create a class named Programmer that inherits from Human, another programmer can create a third class, SeniorProgrammer, that inherits from your derived class:

Public Class SeniorProgrammer : Inherits Programmer
  '*** can this class override Speak?
End Class

Given the class definitions for Human, Programmer, and SeniorProgrammer (which now form the inheritance hierarchy shown in Figure 5.1), ask yourself the following question: Should the author of SeniorProgrammer be able to override the Programmer implementation of Speak? The answer is yes. A method that is declared with the Overrides keyword is itself overridable. The author of SeniorProgrammer can override the implementation of Speak in Programmer with the following code:

Public Class SeniorProgrammer : Inherits Programmer
  Public Overrides Function Speak() As String
    '*** overriding implementation
  End Function
End Class

You can take this example one step further by creating a class named SuperSeniorProgrammer that inherits from SeniorProgrammer. SuperSeniorProgrammer would be able to override the SeniorProgrammer definition of the Speak method with yet another implementation.

If you take this example to the logical extreme, you can create as many classes as you want in the inheritance hierarchy, with each class inheriting from the one above it and overriding the Speak method with a new implementation. There isn't really a theoretical limitation on how many levels you can design in an inheritance hierarchy. In reality, practical limitations often determine how many levels of inheritance you should allow. A few examples will demonstrate how you can limit the use of inheritance to keep a complicated design from getting out of hand.

Suppose you've created a definition for Programmer by inheriting from Human. From your perspective, you are the beneficiary of inheritance because you were able to reuse code from Human and you saved yourself a good deal of time in doing so. However, if you allow other programmers to inherit from your derived class, you must also live up to the responsibilities of a base class author. That includes documenting the semantics for all of your overridable methods.

When you override a method using the Overrides keyword, your method definition becomes overridable by default. You can reverse this default behavior by adding the NotOverridable keyword before the Overrides keyword. This technique is used here to prevent the continued overriding of the Speak method:

Public Class Programmer : Inherits Human
  Public NotOverridable Overrides Function Speak() As String
    '*** overriding implementation
  End Function
End Class

Class SeniorProgrammer : Inherits Programmer
  '*** this class cannot override Speak
End Class

The author of SeniorProgrammer is no longer allowed to override the Speak method. As this example illustrates, when you declare an overriding method implementation with the NotOverridable keyword, that choice simplifies your design. You don't have to worry about other classes inheriting from your class and breaking the semantics of your method.

Using the NotOverridable keyword allows you to disallow overriding on a method-by-method or a property-by-property basis, but another option can make life even easier. Recall that you can disallow inheriting altogether by using the NotInheritable keyword. This keyword is applicable to base classes as well as derived classes such as Programmer:

Public NotInheritable Class Programmer : Inherits Human
  Public Overrides Function Speak() As String
    '*** overriding implementation
  End Function
End Class

Now classes may no longer inherit from Programmer. This choice really simplifies things because you don't have to worry about a contract of behavior between Programmer and derived classes. Sometimes it makes sense to define overridden methods and properties as NotOverridable; at other times it's better to define a derived class as NotInheritable. Both techniques simplify the overall design of a derived class.

Most software developers agree that keeping a design as simple as possible is beneficial. But there's another good reason to apply the NotOverridable and NotInheritable keywords whenever you can: They can also improve performance.

Recall that overridable methods require the use of dynamic binding and, therefore, may incur a runtime cost. Judicious use of the NotOverridable and NotInheritable keywords allows the Visual Basic .NET compiler to employ static binding rather than dynamic binding at times, thereby reducing execution time.

For example, imagine Programmer is defined with the NotInheritable keyword. The Visual Basic .NET compiler can make the assumption that a reference variable of type Programmer will only reference an object created from the Programmer class. That is, the client will never use a Programmer reference variable to access an object of some class derived from Programmer. Because Programmer is sealed, a Programmer reference variable can only be used to access objects created from Programmer. There is no opportunity for polymorphism and, consequently, no need to use dynamic binding. In such a case, the compiler will optimize calls by using static binding instead of dynamic binding.

MyBase versus MyClass versus Me

While we're on the topic of static binding versus dynamic binding, it makes sense to discuss some subtle differences between the keywords Me, MyClass, and MyBase. All three can be used inside a method implementation of a class to refer to a class member, but they can exhibit quite different behavior.

Listing 5.5 summarizes the class definitions we have discussed so far: Human, Programmer, and SeniorProgrammer. Study the listing, and determine which methods are invoked using static binding and which are invoked using dynamic binding.

Listing 5.5 An inheritance hierarchy with statically and dynamically bound methods

Public Class Human
  Public Overridable Function Speak() As String
    Return "I am a human"
  End Function
End Class

Public Class Programmer : Inherits Human
  Public Overrides Function Speak() As String
    Return "I am a programmer"
  End Function

  Public Sub GetInfo()
    '*** what happens when you call Speak from this method?
  End Sub
End Class

Public Class SeniorProgrammer : Inherits Programmer
  Public Overrides Function Speak() As String
    Return "I am a senior programmer"
  End Function
End Class

Listing 5.5 includes three different definitions of the Speak method. The Programmer class overrides the definition of Speak from its base class, then is itself overridden again by the derived class SeniorProgrammer. Notice that the Programmer class now contains an additional method named GetInfo. Imagine you wrote the following definition for this method:

'*** method definition in Programmer class
Public Sub GetInfo()
  Dim message1, message2, message3, message4 As String
  message1 = MyBase.Speak()
  message2 = MyClass.Speak()
  message3 = Me.Speak()
  message4 = Speak()

  Console.WriteLine(message1)   '*** ?
  Console.WriteLine(message2)   '*** ?
  Console.WriteLine(message3)   '*** ?
  Console.WriteLine(message4)   '*** ?
End Sub

As you can see, there are four different ways to call the Speak method. The question is, What does the method output? The answer: The output depends on the type of object. First, suppose you call GetInfo using a reference variable of type Human:

Dim h1 As Human = New Human
h1.GetInfo()

This code fails to compile because the Human class does not contain a method called GetInfo—just making sure you were awake! Next, suppose you call GetInfo using a reference variable of type Programmer that refers to a Programmer object:

Dim p1 As Programmer = New Programmer
p1.GetInfo()

The method call outputs the following to the console window:

I am a human
I am a programmer
I am a programmer
I am a programmer

That should make sense, because the base class of a Programmer is Human. Finally, suppose you call GetInfo using a reference variable of type Programmer that refers to a SeniorProgrammer object:

Dim p2 As Programmer = New SeniorProgrammer()
p2.GetInfo()

Here is the resulting output:

I am a human
I am a programmer
I am a senior programmer
I am a senior programmer

The explanation of this result is a little more subtle. While the object is of type SeniorProgrammer, the method being called is defined inside the Programmer class. Therefore, this example illustrates a case where the Programmer class has other classes both above it and below it in the inheritance hierarchy that can affect what happens at runtime.

What happens when this call to p2.GetInfo executes?

  • When GetInfo calls MyBase.Speak, the Visual Basic .NET compiler uses static binding to invoke the implementation of Speak within the base class—in this case the Human class, because Programmer inherits from Human.

  • When it calls MyClass.Speak, the compiler use static binding to invoke the implementation of Speak in the calling method's class—in this case Programmer because GetInfo is defined within Programmer.

  • When it calls Me.Speak, the compiler uses dynamic binding to invoke the most-derived implementation of Speak—in this case it is defined in SeniorProgrammer.

If you call Speak without using one of these three keywords, it has the exact same effect as calling Me.Speak—namely, it uses dynamic binding.

Calls through the MyBase and MyClass keywords always result in static binding to the base class and the current class, respectively. Calls through the Me keyword result in dynamic binding whenever the method being called is declared as overridable. Each of these keywords can be useful in certain scenarios.

Shadowing Methods

While most uses of static binding are relatively straightforward, this is not always the case. In certain situations, static binding can become complex and non-intuitive. In particular, it can be tricky when a base class and a derived class have one or more member definitions with the same name. An example will demonstrate this point.

Suppose we return to Listing 5.3, where the Human class defines Speak as a statically bound method. What would happen if the Programmer class also supplied a method called Speak? In other words:

Public Class Human
  Public Function Speak() As String
    Return "I am a human"
  End Function
End Class

Public Class Programmer : Inherits Human
  Public Function Speak() As String
    Return "I am a programmer"
  End Function
End Class

Both class definitions contain a method named Speak with the same calling signature. When a member in a derived class is defined in this manner with the same name as a non-overridable member in its base class, the technique is called member shadowing. That is, the Programmer class definition of Speak shadows the Human class definition of Speak.

Listing 5.6 A derived class that shadows a method of its base class

Public Class Human
  Public Function Speak() As String
    Return "I am a human"
  End Function
End Class

Public Class Programmer : Inherits Human
  Public Shadows Function Speak() As String
    Return "I am a programmer"
  End Function
End Class

The Visual Basic .NET compiler produces a compile-time warning when you shadow an inherited member. This warning is meant to raise a red flag so you can avoid shadowing if you have stumbled upon it accidentally. If you want to deliberately shadow a member from a base class, you can suppress the compiler warning by making your intentions explicit with the Shadows keyword, as shown in Listing 5.6.

In a few rare situations, an experienced class designer may decide to use shadowing. The most common scenario where shadowing occurs is when the base class author adds new members to a later version. Imagine that you created the Programmer class by inheriting from an earlier version of the Human class that did not contain a Speak method. Therefore, at the time when you added the public Speak method to the Programmer class, it did not conflict with any of the methods inherited from its base class.

What would happen if the author of the Human class decided to add a public Speak method in a later version of the class? You would then face the dilemma of either removing the Speak method from the Programmer class or shadowing the Speak method from the Human class. A few other scenarios call for shadowing, but this one is probably the most common.

You should do your best to avoid shadowing members from a base class, because member shadowing creates ambiguities that make it easy for a client-side programmer to get into trouble. The problem with member shadowing is that it is based on static binding and, consequently, produces inconsistent results.

The following example will demonstrate where shadowing a member in a base class can create a good deal of confusion. Imagine you're writing client-side code in which you will create an object of type Programmer. Assume the Programmer class is defined as shown in Listing 5.6, where Programmer contains a Speak method that shadows the Speak method in the Human class.

To understand what's going on, you must remember how static binding works: The reference variable's type controls method invocation. Now look at the following code:

Dim programmer1 As Programmer = New Programmer
Dim human1 As Human

Dim message1, message2 As String
message1 = programmer1.Speak()  '*** calls Programmer.Speak()
message2 = human1.Speak()       '*** calls Human.Speak()

The reference variable named programmer1 is of type Programmer. Therefore, invoking the Speak method through programmer1 will result in invoking the implementation defined in the Programmer class. Likewise, the reference variable named human1 is of type Human. Therefore, invoking the Speak method through human1 will result in invoking the implementation defined in the Human class. The strange thing about this example is that a single object responds in different ways to a call of Speak depending on the type of reference that is used to access the object. Dynamic binding produces much more intuitive results because the type of object—not the type of reference—determines which method is actually executed.

To make matters worse, it is legal to shadow an overridable method. However, shadowing an overridable method is something you rarely want to do. This possibility is mentioned here only as a warning that sloppy syntax can result in shadowing by mistake. This kind of mistake is likely to lead to trouble. For example, what happens when a base class defines an overridable method, and a derived class author attempts to override it but forgets to use the Overrides keyword? The compiler produces a warning but still compiles your code as if you had used the Shadows keyword:

Public Class Human
  Public Overridable Function Speak() As String
    '*** default implementation
  End Function
End Class

Public Class Programmer : Inherits Human
  '*** author forgot to use Overrides keyword
  Public Function Speak() As String
      '*** method shadows Human.Speak
  End Function
End Class

Shadowing Overloaded Methods and Properties

Shadowing can become even more complicated when it involves methods and properties that have been overloaded. Recall that the name for a method or property can be overloaded with multiple implementations that differ in terms of their parameter lists. Let's look at an example in which the Human class contains two overloaded methods named Speak, and then the Programmer class inherits from Human and defines Speak so that it shadows one of the inherited methods:

Public Class Human
  Public Function Speak() As String
    Return "I am a human"
  End Function
  Public Function Speak(ByVal message As String) As String
    Return "I am a human who says " & message
  End Function
End Class

Public Class Programmer : Inherits Human
  Public Function Speak() As String
    Return "I am a programmer"
  End Function
End Class

In this example, the definition of the Speak method in the Programmer class will shadow the definition of the Speak method in the Human class with the matching signature. What you might not expect is that the other overloaded definition of Speak within Human is hidden as well. Thus the method with the signature Speak(String) is not part of the Programmer class definition. For this reason, the semantics of shadowing in Visual Basic .NET are sometimes referred to as hide-by-name.

If you try to compile these two class definitions, you will receive another compiler warning. As before, you can suppress this warning by adding the Shadows keyword to the definition of the Speak method in Programmer, as depicted in Listing 5.7.

Listing 5.7 Shadowing an overloaded method

Public Class Human
  Public Function Speak() As String
    Return "I am a human"
  End Function

  Public Function Speak(ByVal message As String) As String
    Return "I am a human who says " & message
  End Function
End Class

Public Class Programmer : Inherits Human
  Public Shadows Function Speak() As String
    Return "I am a programmer"
  End Function

  '*** hides Speak(String) from base class
End Class

You might ask why the Visual Basic .NET compiler requires you to use the Shadows keyword to suppress the compiler warning in this situation. To understand the motivation behind this requirement, ask yourself the following question: Should the definition for the method with the signature Speak() in the Programmer class hide every definition of Speak in the Human class, or should it just shadow the one with the matching signature? In this case the Shadows keyword indicates that every implementation of Speak in the Human class should be hidden from clients programming against the definition of Programmer.

There's a subtle yet important difference between shadowing a method and hiding a method. In Listing 5.7, the method Speak() is shadowed, whereas the method Speak(String) is hidden. The shadowed method is still accessible to clients through the derived class definition, but the hidden method is not. Take a look at the following client-side code to see the difference. This code creates only one object of type Programmer, yet accesses this same object through two different reference variables:

Dim programmer1 As Programmer = New Programmer
Dim human1 As Human

Dim message1, message2, message3, message4 As String

'*** access object through derived class reference
message1 = programmer1.Speak()         '*** calls Programmer.Speak()
message2 = programmer1.Speak("Hello")  '*** error: method doesn't exist

'*** access object through base class reference
message3 = human1.Speak()              '*** calls Human.Speak()
message4 = human1.Speak("Hello")       '*** calls Human.Speak(String)

As this example reveals, member hiding has a strange side effect. An object created from the Programmer class still provides a definition for Speak(String)—as evidenced by the fact that human1.Speak("Hello") works. However, the Speak(String) method is accessible only to clients that are accessing the object through a reference variable of type Human. As this example involves static binding, a call to Speak() through a reference variable of type Human will use the method definition from Human. Thus hiding doesn't remove a method or property definition from an object; it simply makes a member inaccessible to clients that use reference variables based on the derived class.

You've just seen how Visual Basic .NET allows you to shadow and hide methods using hide-by-name semantics with the Shadows keyword. It also allows you to use the Overloads keyword instead of the Shadows keyword in situations in which you would rather achieve hide-by-signature semantics. With this technique, you can shadow an overloaded method from a base class without hiding other method definitions of the same name. Let's revisit Listing 5.7 and make one minor modification:

Public Class Human
  Public Function Speak() As String
    Return "I am a human"
  End Function

  Public Function Speak(ByVal message As String) As String
    Return "I am a human who says " & message
  End Function
End Class

Public Class Programmer : Inherits Human
  Public Overloads Function Speak() As String
    Return "I am a programmer"
  End Function

  '*** inherits Speak(String) from base class
End Class

The only change that has been made to this code from Listing 5.7 is that the Overloads keyword has replaced the Shadows keyword in the Programmer class definition of Speak(). This change has the effect of shadowing a method by signature as opposed to hiding it by name. The result is that class Programmer now makes the definition of Speak(String) accessible to clients:

Dim programmer1 As Programmer = New Programmer
Dim human1 As Human

Dim message1, message2, message3, message4 As String

'*** access object through derived class reference
message1 = programmer1.Speak()         '*** calls Programmer.Speak()
message2 = programmer1.Speak("Hello")  '*** calls Human.Speak(String)

'*** access object through base class reference
message3 = human1.Speak()              '*** calls Human.Speak()
message4 = human1.Speak("Hello")       '*** calls Human.Speak(String)

It's now possible to call Speak() and Speak(String) using a reference variable of type Programmer or a reference variable of type Human. One of these method signatures is shadowed, and the other is inherited directly from Human to Programmer. Calls to Speak() are dispatched to either the Human class definition or the Programmer class definition depending on the type of reference variable used. Calls to Speak(String) are always dispatched to the definition in the Human class.

The Overloads keyword should be used on some occasions that do not involve any form of hiding or shadowing. For example, you might want to add a method to a derived class that shares the same name as one or more methods in its base class but doesn't match any of their parameter lists. Suppose you wanted to create a new class that inherits from our running definition of Human (see Listing 5.7). What if you decided to add a third method named Speak that had a signature that was different from the two signatures of Speak inherited from Human? This scenario does not involve either shadowing or hiding, but you can and should use the Overloads keyword:

Class Programmer : Inherits Human
  '*** inherits Speak() from base class
  '*** inherits Speak(String) from base class

  Public Overloads Function Speak(ByVal excited As Boolean) As String
    If excited Then
      Return "Oh boy, I am an excited programmer"
    Else
         Return "I am a programmer"
    End If
  End Function
End Class

Now the Programmer class supports three overloaded versions of Speak. Two implementations of Speak are inherited from Human, and a third implementation is added to the Programmer class. Notice that you would get very different results if you do not use the Overloads keyword in the Speak(Boolean) method definition of the Programmer class. If you omit this keyword, the Visual Basic .NET compiler would once again default to using the Shadows keyword. In that case, the Programmer class would contain only one definition of Speak, not three.

Clearly, a design in which members are shadowed and/or hidden has the potential to catch programmers off guard. The shadowing of fields, methods, and properties results in multiple definitions with the same name. Confusion may arise because different types of reference variables produce inconsistent results when accessing the same object.

While most of this discussion has dealt at length with the complexities of shadowing and hiding, you most likely will not have to deal with these topics on a regular basis. In fact, the complexities discussed over the last several pages explain why most designers try their best to avoid designs involving shadowing and hiding. You are well advised to follow suit and avoid the use of shadowing and hiding when you design and implement your own classes.

  • + Share This
  • 🔖 Save To Your Account

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020