Polymorphism is the ability of a class to take on different functionality based on the context in which it is used. Polymorphism is chiefly implemented in most OOP languages using techniques called method overloading, overriding, and shadowing.
Overloading is how we can create methods that have the same name but accept many different argument parameters. We can overload methods we create and we can overload methods we override. Suppose we want to create a function that, if passed numbers, adds the two numbers and returns the result, but if passed strings, concatenates the strings and returns the result.
Public Function Add(ByVal intA As Integer, _ ByVal intB As Integer) as Object Dim intC As Integer intC = intA + intB Return intC End Function Public Function Add(ByVal strA As String, _ ByVal strB As String) as Object Dim strC As String strC = strA & strB Return strC End Function
There are a couple of things to notice in the example. First, both versions of the Add function return data types of Object. While the overloaded functions can have different parameters, they must return the same type. Since Object is the root class of the entire class library, it can accept any data type. This is currently the only way to return data of different types from an overloaded function. Second, they don't include the keyword Overloads. This is because as long as they are declared in the same class, the overload is implicit. The only time we need to explicitly use Overloads is when we are overloading a method in the base class. Suppose the first function were in ClassA. If in ClassB we want to overload it, we would use this syntax:
Public Overridable Function Add(ByVal intA As Integer, _ ByVal intB As Integer) As Object Dim intC As Integer intC = intA + intB Return intC End Function
ClassB (inherits ClassA) Function:
Public Overloads Function Add(ByVal strA As String, _ ByVal strB As String) As Object Dim strC As String strC = strA & strB Return strC End Function
Note that this does not override the function. The original function in ClassA is still available. If you include Overrides and Overloads in the same declaration you will generate an error.
When a class inherits from another class, it has all the properties and methods of the first class. Without doing anything, you can access all of them. However, what is the point of inheriting? It isn't just to create another data type with the same functionality as the first. The point of inheriting is to retain the functionality of the first, and add more and change some of the existing. Adding more functionality is easy. We just add more properties and methods to implement the new functionality. However, what if we want to change or enhance existing functionality. Do we have to create it all over again? That would seem to undo the benefits of inheritance. This is where overriding comes in.
We can override a method in the parent class and replace its functionality with new. Suppose a class has this method:
Public Overridable Function Sum(ByVal intA As Integer, _ ByVal intB As Integer) As Integer Dim intC As Integer intC = intA + intB Return intC End Function
Note Overridable in the declaration. This enabled the function to be overridden in a derived class. In the derived class we can then override the function and make it do something else:
Public Overrides Function Sum(ByVal intA As Integer, _ ByVal intB As Integer) As Integer Dim intC As Integer intC = intA - intB Return intC End Function
The function template can be created easily by selecting (Overrides) in the class drop down on the code window and then selecting the method you wish to override in the method drop down. This override actually changes the Sum method to a subtraction, not advisable in real life, but okay for illustration. Suppose we want to use the existing functionality and then add to it. We can do this:
Public Overrides Function Sum(ByVal intA As Integer, _ ByVal intB As Integer) As Integer Dim intC As Integer Dim intD As Integer intC = MyBase.Sum(intA, intB) intD = intA * intC Return intD End Function
This overridden method calls the parent (or base) class's add method first, preserving the existing functionality, using the MyBase keyword. It then performs additional processing on the result of the call to the base-class method before returning it to the caller. In actual practice we would not make a Sum method do anything but add the two arguments, but it is an extreme example of how you can change the functionality in derived classes.
Shadowing masks the Overridable method in the base class with a method of the same name. The parameter signature does not have to be the same. It effectively creates a method with the same name as a method in the base class, but they are completely independent from each other. Do not use this. I can't think of one good reason to use the Shadows keyword. Moreover, there is a way to shadow a method without even knowing it, called an implicit shadow. Just for completeness I will demonstrate both ways. That way you can avoid implicit shadows.
We will use our Sum procedure described earlier. First, the explicit shadow:
Public Shadows Function Sum(ByVal strA As String, _ ByVal StrB As String) As String Dim strC As String strC = strA & strB Return strC End Function
Notice that the parameters are strings this time. We could also have just as legally done this:
Private Shadows Sub Sum() ' Do nothing End Sub
This would effectively mask the method from the users of your class. This is one of the possible uses of the Shadows keyword that I grudgingly will allow.
Here is one that I've seen experienced OOP programmers stumble over:
Public Overridable Function Sum(ByVal intA As Integer, _ ByVal intB As Integer) As Integer Dim intC As Integer intC = intA * intB return intC End Function
Notice that it multiplies the two arguments. Here is the real insidious thing about it. Because we declared this as Overridable, it implicitly shadows the method in the base class. The IDE does warn you about this, but it is easy to dismiss the warning without paying much attention to it. What will happen here is that any classes derived from this one will multiply the two arguments, because we have masked the functionality of the base class and replaced it with this method.
The bottom line is do not shadow. It creates a dangerous, confusing class structure and should not be used. If anyone can come up with a valid reason to use shadows, I would appreciate an email at mailto:firstname.lastname@example.org.