2

Here's what I've got on a command button; it's just creating variables and attempting to output their ID (which should be an instance variable inherited from the base class.)

Private Sub Command1_Click()
    Dim ball1 As Ball, ball2 As Ball
    Dim cube1 As Cube, cube2 As Cube

    Set ball1 = New Ball
    Set cube1 = New Cube
    Set cube2 = New Cube
    Set ball2 = New Ball

    MsgBoxTheID (ball1)  'errors; should be 0
    MsgBoxTheID (ball2)  'errors; should be 3
    MsgBoxTheID (cube1)  'errors; should be 1
    MsgBoxTheID (cube2)  'errors; should be 2

    Call ball1.MsgBoxID  ' works; displays 0
    Call ball2.MsgBoxID  ' works; displays 3
    Call cube1.MsgBoxID  ' works; displays 1
    Call cube2.MsgBoxID  ' works; displays 2

End Sub

Modeul1.bas:

Global globalID As Integer

Public Sub MsgBoxTheID(theObj As BaseObj)
    ' this function is meant to accept objects of type Ball, Cube, and BaseObj
    MsgBox theObj.ID
End Sub

BaseObj Class Module:

Public ID As Integer
Public isVisible As Boolean

Public Sub setVisiblity(newVis As Boolean)
    isVisible = newVis
End Sub

Public Sub MsgBoxID()
    MsgBox ID
End Sub

Private Sub Class_Initialize()
    ID = globalID
    globalID = globalID + 1
End Sub

Ball Class Module:

Implements BaseObj
Private theObj As BaseObj
Public radius As Double

Private Property Let BaseObj_ID(ByVal RHS As Integer)
End Property
Private Property Get BaseObj_ID() As Integer
End Property
Private Property Let BaseObj_isVisible(ByVal RHS As Boolean)
End Property
Private Property Get BaseObj_isVisible() As Boolean
End Property

Public Sub MsgBoxID()
    Call theObj.MsgBoxID
End Sub

Private Sub BaseObj_MsgBoxID()
    Call theObj.MsgBoxID
End Sub

Public Sub BaseObj_setVisiblity(newVis As Boolean)
End Sub

Private Sub Class_Initialize()
    Set theObj = New BaseObj
End Sub

Cube Class Module:

Implements BaseObj
Private theObj As BaseObj
Public sideLength As Double

Private Property Let BaseObj_ID(ByVal RHS As Integer)
End Property
Private Property Get BaseObj_ID() As Integer
End Property
Private Property Let BaseObj_isVisible(ByVal RHS As Boolean)
End Property
Private Property Get BaseObj_isVisible() As Boolean
End Property

Public Sub MsgBoxID()
    Call theObj.MsgBoxID
End Sub

Private Sub BaseObj_MsgBoxID()
    Call theObj.MsgBoxID
End Sub

Public Sub BaseObj_setVisiblity(newVis As Boolean)
End Sub

Private Sub Class_Initialize()
    Set theObj = New BaseObj
End Sub

There are several things I don't like about this, two of which I am of the impression are unavoidable: (1) the fact that it's a mess compared to C++, and (2) the fact that the Ball and Cube classes merely contain an object of BaseObj type. They are not actually inheriting anything from BaseObj; they are only being forced to implement the same interface (whoopty doo.)

To make matters worse, and this is the one that I am truly hoping is rectifiable, they do not seem to be able to fill in for an object of the base class when it comes to parameter passing.

Am I doing something wrong?

TimFoolery
  • 1,895
  • 1
  • 19
  • 29
  • Just a quick note. Your BaseObj has a method called `setVisiblity`. But it is redundent because you also have a *Public* isVisible variable. When you declare something as Public in a class it becomes part of its public interface. Get used to declaring those class variables as Private. This will clean up the code a bit too. – tcarvin Jul 17 '12 at 13:09
  • @tcarvin Yeah, this was just some junk that I threw together to attempt to use polymorphism for the first time. – TimFoolery Jul 17 '12 at 17:25

3 Answers3

4

Visual Basic 6 is not the ideal language with which to learn the "purer" form of OOP. VB6 was designed to implement a very much hybridized version of object-based programming that orbited the Microsoft Component Object Model (COM) world, with its interface inheritance orientation. VB6 does not support implementation inheritance, which tends to make the kind of polymorphism you're looking for hard to do.

There are a few tricks I recall from the VB6 era to "get around" (sort of) the implementation inheritance problem, particularly when it comes to substituting an object of a base class for a subclass. One trick I remember is to declare a property procedure of the type of the base interface that returns a reference to "Me" as the return type. That "tricks" the runtime into providing the conversion into the desired interface. There's another magic trick to make a property the "defaut" property by setting its "procedure number" to -4 in one of VB6's design dialogs.

The point? If you're really wanting to get into conventional OO programming, don't try to learn it with VB6 if you don't have to. Move up to (at least) VB.NET, C#, or Java. I don't say that as a VB6 hater - heck, knowing these stupid details paid the bills for a long time - but its a tough nut to crack to translate its own little idiosyncrasies into a good, fundamental understanding of OOP.

Good luck!

David W
  • 10,062
  • 34
  • 60
  • +1 Here are some links to descriptions of the workarounds. [MSDN magazine](http://msdn.microsoft.com/en-us/library/aa260821(v=vs.60).aspx) and [Rockford Lhotka](http://www.lhotka.net/Article.aspx?id=5f76a91c-5a75-49e1-9379-6d2807653b68). – MarkJ Jul 17 '12 at 15:34
3

You've figured out how to fix the error, but I'll contribute the "why".

In VB6 (and VB5, etc), there are two syntaxes for invoking a method/function/subroutine/statement. The first is this:

MySubName arg1, arg2, arg3, arg4

Blech, I know it is my bias from C and Java, but I like to see parenthesis around my argument list. That sytax is this:

Call MySubName(arg1, arg2, arg3, arg4)

So those two are equivilent.

What you ran into is not the effect of the Call. What you ran into is the effect of the unneeded parenthesis in the non-Call version. The parenthesis force the statement/arg inside them to be evaluated before the rest of the statement (think math order of operation).

So this:

SomeSub (arg1)

Is like this:

temp = (arg1) 
SomeSub temp

Further, objects in VB6 can have a "default property". This lets you write code like this:

Dim name as String
name = txtName

Instead of assigne the textbox object reference to name, the default property of .Text is used, and the result is like this:

Dim name as String
name = txtName.Text

So when you tried to evaluate SomeSub (arg1) I think it would attempt to locate and execute the default property of your object and pass that value to SomeSub.

tcarvin
  • 10,715
  • 3
  • 31
  • 52
  • Well don't I feel stupid. :S Sad thing is that I know better, but I guess it's been years since I've made that mistake, and I couldn't identify the real problem based on the description of the error. – TimFoolery Jul 17 '12 at 17:32
  • @Michael Oh no, it is not obvious at all. Especially if you write in multiple languages and go back and forth. The parens, plus forgeting to use `Set` are the most common ommisions. That is why I *always* use the `Call` syntax. It is explicit and prevent that accidental evaluation. – tcarvin Jul 17 '12 at 17:55
0

Well, I figured it out, sort of.

MsgBoxTheID (ball1)  'errors; should be 0
MsgBoxTheID (ball2)  'errors; should be 3
MsgBoxTheID (cube1)  'errors; should be 1
MsgBoxTheID (cube2)  'errors; should be 2

...needs to be changed to...

Call MsgBoxTheID (ball1)  'errors; should be 0
Call MsgBoxTheID (ball2)  'errors; should be 3
Call MsgBoxTheID (cube1)  'errors; should be 1
Call MsgBoxTheID (cube2)  'errors; should be 2

... even though MsgBoxTheID has no return type, which is weird because I always thought Call was simply something that you could use to discard the return value without having to declare a variable, like so:

dim unneededVar as Integer
unneededVar = FunctionNameThatReturnsAnInteger()

But I guess not. So... I'll have to go read up on exactly what the Call statement is doing to make this example program work, but it's definitely working now. (I also had to add BaseObj_ID = theObj.ID to the Property Get BaseObj_ID() As Integer methods in the classes that were implementing BaseObj.)

TimFoolery
  • 1,895
  • 1
  • 19
  • 29
  • Here is some explanation about the Call statement and the meaning of the parentheses http://stackoverflow.com/a/479904/15639 – MarkJ Jul 17 '12 at 15:38