Shadows and Overrides and Bears, Oh My!

  • Thread starter Thread starter Christopher W. Douglas
  • Start date Start date
C

Christopher W. Douglas

I am developing a VB.NET app using Visual Studio.NET 2003. VB.NET allows
me to create a class with two or more methods that have the same name, as
long as they have different (non-optional) arguments, such as:

FirstClass
Public Sub Populate(string)
Public Sub Populate(string, string)

I don't have to use Overloads, because both methods are in the same class.

I also understand that through inheritance, I can have a class that
derives from a base class, and the derived class inherits methods:

BaseClass
Public Sub Populate(string)

FirstClass
(Has Populate(string) available)

Now, if I need to replace the Populate method in another class, I use
Protected and Overrides:

BaseClass
Protected Overridable Sub Populate(string)

FirstClass
(Has Populate(string) available)

SecondClass
Public Overrides Sub Populate(string)
* different code here *

Through what I *think* is polymorphism, I can have another class call the
Populate method of either FirstClass or SecondClass:

OtherClass
PopulateClass(a as BaseClass, mystring as String)
a.Populate(mystring)

PopulateClass can be passed either a FirstClass or a SecondClass object, and
the populate method will be called.

Now, what I want to do is have two methods with the same name but
different signatures, such as:

BaseClass
Protected Sub Populate(string)

FirstClass
(Has Populate(string) available)

SecondClass
Public Overloads? Overrides? Shadows? Sub Populate(string)
Populate Overloads? Overrides? Shadows? Sub Populate(string, integer,
integer)

The trouble is, I can't figure out whether to use Shadows, Override or
Overloads. I get an error if I only use Shadows on one method, and the
*base* method is called if I use Overrides or Overloads. Can someone help
me out here?
 
Use Overloads when you want to create multiple methods which differ only in
the parameters

Use Overrides, when you have a overridable method in a base class and you
want to circumvent that in the derived class, using the same method signature

Use Shadows when you have a non-overridable/overridable method in a base
class and you want to circumvent that with a new method signature (change in
access specifiers as well)
 
ANSWER at end

The Overloads is your tricky wicket here with polymorphism. Late binding
just makes it more complex. Here is some sample code that might illustrate
what you are going through. Class3 is Shadows, Class4 is Overloads. You will
see it does not really matter much.

----------------------------------------------------------------------
Module Module1

Sub Main()

Dim a As New Class1
Dim b As New Class2
Dim c As New Class3
Dim d As New Class4
Dim someString As String = "some string"

Dim pop As New Populator

pop.PopulateClass(a, someString)
Console.WriteLine(" ")
pop.PopulateClass(b, someString)
Console.WriteLine(" ")
pop.PopulateClass(c, someString)
Console.WriteLine(" ")
pop.PopulateClass(d, someString)

Console.Read()

End Sub

End Module

Public Class Populator

Public Sub PopulateClass(ByRef a As Class1, ByVal b As String)
Console.WriteLine("Input Type")
Console.WriteLine(a.GetType())

a.Populate(b)

Dim thisType As String = a.GetType().ToString()

Console.WriteLine("Running as own Class Type:")

Select Case (a.GetType().ToString())
Case "Polymorph.Class1"
Dim c As Class1 = CType(a, Class1)
Console.WriteLine(a.GetType())
c.Populate(b)
Case "Polymorph.Class2"
Dim c As Class2 = CType(a, Class2)
Console.WriteLine(a.GetType())
c.Populate(b)
Case "Polymorph.Class3"
Dim c As Class3 = CType(a, Class3)
Console.WriteLine(a.GetType())
c.Populate(b)
Case "Polymorph.Class4"
Dim c As Class4 = CType(a, Class4)
Console.WriteLine(a.GetType())
c.Populate(b)
End Select
End Sub

End Class

Public Class Class1
Public Overridable Sub Populate(ByVal param As String)
Console.WriteLine(param & " - from Class1.Populate(string)")
End Sub

Public Overridable Sub Populate(ByVal param As String, ByVal param2 As
String)
Console.WriteLine(param & " - from Class1.Populate(string, string)")
End Sub

End Class

Public Class Class2
Inherits Class1

End Class

Public Class Class3
Inherits Class1

Public Shadows Sub Populate(ByVal param As String)
Console.WriteLine(param & " - from Class3.Populate(string)")
End Sub

End Class

Public Class Class4
Inherits Class1

Public Overloads Sub Populate(ByVal param As String)
Console.WriteLine(param & " - from Class3.Populate(string)")
End Sub

End Class
----------------------------------------------------------------------

The output is as follows:

----------------------------------------------------------------------
Running as own Class Type:
Polymorph.Class1
some string - from Class1.Populate(string)

Input Type
Polymorph.Class2
some string - from Class1.Populate(string)
Running as own Class Type:
Polymorph.Class2
some string - from Class1.Populate(string)

Input Type
Polymorph.Class3
some string - from Class1.Populate(string)
Running as own Class Type:
Polymorph.Class3
some string - from Class3.Populate(string)

Input Type
Polymorph.Class4
some string - from Class1.Populate(string)
Running as own Class Type:
Polymorph.Class4
some string - from Class4.Populate(string)

----------------------------------------------------------------------

Now, here is the way to solve this tricky problem:

1. Turn Option Strict Off - as much as I loath this, there are times it is
necessary

Option String Off 'This goes as top of page

2. Change the PopulateClass() signature

Public Sub PopulateClass(ByRef a As Object, ByVal b As String)

Run the program again and this is the output:

----------------------------------------------------------------------
Input Type
Polymorph.Class1
some string - from Class1.Populate(string)
Running as own Class Type:
Polymorph.Class1
some string - from Class1.Populate(string)

Input Type
Polymorph.Class2
some string - from Class1.Populate(string)
Running as own Class Type:
Polymorph.Class2
some string - from Class1.Populate(string)

Input Type
Polymorph.Class3
some string - from Class3.Populate(string)
Running as own Class Type:
Polymorph.Class3
some string - from Class3.Populate(string)

Input Type
Polymorph.Class4
some string - from Class4.Populate(string)
Running as own Class Type:
Polymorph.Class4
some string - from Class4.Populate(string)
----------------------------------------------------------------------

Overloads or Shadows? In this case, it is not as important, as a call to
MyBase.Populate(param)

Will still yield:
some string - from Class1.Populate(string)

Overall, I would choose Shadows, as the Overload is identical to the
underlying base implementation. I do not believe this will work in other
..NET langauges. Also, you should really get used to Reflection if there is
ever a chance of programming in another .NET language, as Reflection works
in all languages and Late Binding only works in VB.NET.


--
Gregory A. Beamer
MVP; MCP: +I, SE, SD, DBA

************************************************
Think Outside the Box!
************************************************
 
Cowboy and Rakesh,

Thanks for the responses, but I don't think they answered my basic question.
I have one method in the base class that all derived classes need to be able
to replace, and I want to be able to create other methods with the same name
in the derived classes with different signatures.

I want to be able, without Late Binding and without Option Strict Off, to
have a base class method Populate, which is always overriden by the derived
class. I also want to have other methods named Populate that have different
signatures, so the code knows which one to use based on the arguments
provided.

I want to have another class (or form) with a method that has the base class
as an argument:

DoMyPopulatin(MyObject as BaseObject, a as String)
MyObject.Populate(a)

Then, within each of the derived classes, Populate is replaced with database
code specific to that object. If there is only ONE populate method, I make
it overrides in the derived class:

FirstClass
Public Overrides Sub Populate(a as String)

and everybody is happy. However, if there are TWO populate methods (and I
don't want to make a populate method in the base class for every possible
permutation of derived classes):

FirstClass
Public Overrides Sub Populate(a as String)
Public Shadows Sub Populate(a as String, b as String)

gives me the error: Populate cannot override a method that has been
shadowed. While this:

FirstClass
Public Overrides Sub Populate(a as String)
Public Shadows Sub Populate(a as String, b as String)

gives me the error: sub 'Populate' shadows an overloadable member declared
in the base class 'BaseClass'. If you want to overload the base method,
this method must be declared 'Overloads'. Now, this:

FirstClass
Public Shadows Sub Populate(a as String)
Public Shadows Sub Populate(a as String, b as String)

or this:

FirstClass
Public Overloads Sub Populate(a as String)
Public Overloads Sub Populate(a as String, b as String)

does not give any errors, but the BASE method is always executed under:

DoMyPopulatin(MyObject as BaseObject, a as String)
MyObject.Populate(a)

Am I asking too much? :^)

I really don't want to use CType or a select statement or anything like
that, because then why bother creating a base class?
 
Rakesh,

AHAH! You gave me the answer. I didn't realize you could have Override
and Overloads in the same function, I thought you had to choose only one (or
none). MustInherit doesn't work for me (I have to use base class objects
too), but this does:

Public Class Base
Public Sub Populate(ByVal a As String)
* No Code in method *
End Sub
End Class

Public Class Derv
Inherits Base

Public Overloads Overrides Sub Populate(ByVal a As String)
End Sub

Public Overloads Sub Populate(ByVal a As String, ByVal b As String)
End Sub
End Class

Using Overloads and Overrides in the same function ensures that the derived
function is called, and an external function like this can be fed a Derv
object:

GetToPopulatin(MyObject as Base, a as String)
MyObject.Populate(a) <---- Calls the Derv class' Populate method
End Sub

Thank you so much for your help.
 
Back
Top