Overloaded Private Function in Module crashes ...

J

Joe HM

Hello -

The following code will crash if the TestA() instances are declared as
Private and work just fine if they are Public.

Is there a way to hide these instances to callers from outside the
Module? It should only be possible to call the one instance of TestA()
without the second argument.

ModuleX
Sub main()
initialize(0)
TestA(0)
End Sub

Public Class cProjectBase
End Class

Public Class cProjectA
Inherits cProjectBase
End Class

Public Class cProjectB
Inherits cProjectBase
End Class

Dim mProjectInstance As Object

Sub initialize(ByVal aFlag As Integer)
If aFlag = 0 Then
mProjectInstance = New cProjectA
End If

If aFlag = 1 Then
mProjectInstance = New cProjectB
End If
End Sub

Public Sub TestA(ByRef aDummy As Integer)
TestA(aDummy, mInstance)
End Sub

Private Sub TestA(ByRef aDummy As Integer, ByRef aX As cProjectA)
Console.WriteLine("TestA for cProjectA")
End Sub

Private Sub TestA(ByRef aDummy As Integer, ByRef aX As cProjectB)
Console.WriteLine("TestA for cProjectB")
End Sub
End Module

Thanks,
Joe
 
W

wooster11

Interesting. I copied the code above and cannot recreate your error.
The only change I made was your reference to mInstance in the
TestA(ByRef aDummy As Integer) function.

The module I created only showed the public functions outside of the
module. I'm a bit confused as to how it crashes. Where in your
debugger does it crash? And what error do you get?

Derek Woo
 
J

Joe HM

Hello -

Sorry for the late reply but I was out for a few days. Here is the
error message I get ...

Unhandled Exception: System.MissingMemberException: Method
'Module1.TestA' cannot be called with 2 argument(s).
at
Microsoft.VisualBasic.CompilerServices.VBBinder.set_InternalThrow(Exception
Value)
at
Microsoft.VisualBasic.CompilerServices.VBBinder.BindToMethod(BindingFlags
bindingAttr, MethodBase[] match, Object[]& args,
ParameterModifier[] modifiers, CultureInfo culture, String[] names,
Object& ObjState)
at
Microsoft.VisualBasic.CompilerServices.VBBinder.InvokeMember(String
name, BindingFlags invokeAttr, Type objType, IReflect
objIReflect, Object target, Object[] args, ParameterModifier[]
modifiers, CultureInfo culture, String[] namedParameters)
at
Microsoft.VisualBasic.CompilerServices.LateBinding.InternalLateCall(Object
o, Type objType, String name, Object[] args, St
ring[] paramnames, Boolean[] CopyBack, Boolean IgnoreReturn)
at
Microsoft.VisualBasic.CompilerServices.LateBinding.LateCall(Object o,
Type objType, String name, Object[] args, String[] p
aramnames, Boolean[] CopyBack)
at ConsoleApplication1.Module1.TestA(Int32& aDummy) in
C:\...\ConsoleApplication1\Module1
..vb:line 38
at ConsoleApplication1.Module1.main() in C:\...\Module1.vb:line 4

It crashes when it executes ...
TestA(aDummy, mProjectInstance)
in the first instance of TestA.

Thanks!
Joe
 
W

wooster11

Joe,
I found your problem and was able to recreate it. The problem is
that you're trying do perform late binding in your code. Since you
declare mProjectInstance as an Object, when you try to pass this to
your overloaded TestA functions, the runtime doesn't know which one to
call. What you need to do is determine what type of object
mProjectInstance is, then ctype that into the the TestA function.
Here's what I did to get it to work:

Public Sub TestA(ByRef aDummy As Integer)
If mProjectInstance.GetType.Equals(GetType(cProjectA)) Then
TestA(3, CType(mProjectInstance, cProjectA))
ElseIf mProjectInstance.GetType.Equals(GetType(cProjectB)) Then
TestA(3, CType(mProjectInstance, cProjectB))
End If
End Sub

Since you don't explicitly have a TestA function that takes an Integer
and an Object as its parameters, the runtime doesn't know which of the
two functions to call. You need to tell it which one to call by
casting the mProjectInstance into the proper type. This should solve
your problem. Let me know if you need anything else.

Derek
 
J

Joe HM

Hello -

Thanks for your help! I used to do a lot of C++ programming and I did
not encounter a problem like that there.

What I am trying to do is have a single function that is called from
the outside and then have that function call the appropriate private
function instance. I wanted to do this without if/elseif statements
within TestA since I have a lot of functions just like TestA and I also
wanted it to be easily expandable.

Why does this work if the TestA instances are Public? I tried to
declare mProjectInstance as cProjectBase but that would not work either
because of "narrowing down" problems. It just seems that something
like that was much easier in C++.

Thanks again!
Joe

How can I declare mProjectInstance
 
W

wooster11

Joe,
It's really a weird occurrence and I can't explain to you why
changing the function to Public works. I've tried other visibilities
and also get an error, albiet a slightly different one, but the same
type of exception.
I don't know enough about VB .NET and the framework to give you a
more decisive answer. I wish that I could.

What I can suggest is to possibly rethink your design... Since you
want specific functions to occur based on the type of object that is
created, why don't you make a function that is overridable in a
function in the base class? The parent class can have a mustoverrides
function that is called and defined by both child classes. This will
let you declare a BaseClass object and call the function that exists in
both the child classes. After you initialize your base object into one
of its child objects, the proper function will be called.
I've modified your code and placed it below. Notice that I make the
function a mustoverride and I override the function in each of the
child classes. Also notice that the base class is a mustinherit. This
may not exactly work for you, but it's worth taking a look at and
possibly thinking of designing your application in a similar way. Let
me know how this goes. And if you have any more questions, feel free
to reply again. Good luck.

Module X
Public Sub main()
initialize(0)
TestA(0)
End Sub

Public MustInherit Class cProjectBase
Protected msg As String

Public MustOverride Sub TestA(ByRef aDummy As Integer)
End Class

Friend Class cProjectA
Inherits cProjectBase

Public Overrides Sub TestA(ByRef aDummy As Integer)
msg = "I'm cProjectA"
MsgBox(msg)
End Sub
End Class

Friend Class cProjectB
Inherits cProjectBase

Public Overrides Sub TestA(ByRef aDummy As Integer)
msg = "I'm cProjectB"
MsgBox(msg)
End Sub
End Class

Private mProjectInstance As cProjectBase

Public Sub initialize(ByVal aFlag As Integer)
If aFlag = 0 Then
mProjectInstance = New cProjectA
End If

If aFlag = 1 Then
mProjectInstance = New cProjectB
End If
End Sub

Public Sub TestA(ByRef aDummy As Integer)
mProjectInstance.TestA(aDummy)
End Sub
End Module
 
J

Joe HM

Hello -

Thanks a lot for your feedback! Yeah ... I like your proposed design
much better. I'll see if I can fit it into the existing code.

Joe
 
W

wooster11

Joe,
One more thing. If you don't want to use mustinherit in your base
class (in case you have a reason to actually use the base class as an
object and not one of its subclasses), you can remove the mustinherit
and change the mustoverride method to a overridable method. You will
need to supply some logic for the base class method, but you will be
allowed to override that parent method in the sub class with its own
custom logic.
See the example of the three classes defined below.

Public Class cProjectBase
Protected msg As String

Public Overridable Sub TestA(ByRef aDummy As Integer)
msg = "I wasn't overrided"
MsgBox(msg)
End Sub
End Class

Friend Class cProjectA
Inherits cProjectBase

Public Overrides Sub TestA(ByRef aDummy As Integer)
msg = "I'm cProjectA"
MsgBox(msg)
End Sub
End Class

Friend Class cProjectB
Inherits cProjectBase

Public Overrides Sub TestA(ByRef aDummy As Integer)
msg = "I'm cProjectB"
MsgBox(msg)
End Sub
End Class
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top