We will now move into a more advanced aspect of VB - OOP. But don't worry, Object Oriented Programming is quite simple, in fact it is probably simpler for those who have never programmed before than for those with long experience of traditional Fortran/Basic/Pascal (pick your favourite imperative language).
You should be familiar with VB's event-driven programming style by now. However I'll explain it again. When you're doing general VB programming, your thoughts should go in this pattern: "If the user does this, what should happen? How would I make it happen?" Then you would write the program to fit the answers to these questions. That is event-driven programming. You program according to what events the user would trigger. Dragging a picture, clicking a button, and typing a word are all events.
You, being the brave coder that you are, would ask: "WHY do I HAVE to think like that??"
Well here's an alternative way for you to think: Object Oriented Programming(OOP). In the world of OOP, you break a problem down into small parts and solve them individually. If you are to program in an object oriented style, you would think of every variable or functions as a property of an object, and everything would seem like an object to you. OOP is hard to explain so you'll have to experience it in the following examples.
Imagine that you have a bottle of juice. What properties does it have? What events does it have?(What can it do?) Here's a list I could think of:
Private Colour As String 'What colour? Private Fruit As String 'What kind of fruit? Private Volume As Single 'How much? Public Sub MakeJuice(c As String, f As String, v As Single) 'Make some Colour = c Fruit = f Volume = v End Sub Public Sub Evaporate() 'Well, that's the only thing I could think of Volume = Volume - 10 End Sub
Behold. That's our first class. Don't worry about anything right now. I will go over those later. Anyway, let's assume that this class is named, "Juice". Think of it as a general description of a bottle of juice. Now we can create an actual bottle of apple juice:
Private AppleJuice As Juice 'Define Set AppleJuice = New Juice 'Create a new instance of Juice AppleJuice.MakeJuice "brown", "apple", 30
AppleJuice.Evaporate '20 units left AppleJuice.Evaporate '10 left AppleJuice.Evaporate 'Yes!!
"Wait", you interrupted my rant once again, "but why do I have to use OOP? Just because you hate apple juice?"
OOP is good for large-scale programming - As your code grows large, there are going to be more and more procedures/functions to your program, and your code is going to be so cluttered that one more look at it, you'd scream. That is why I'm teaching you OOP! (So instead of looking at hundreds of scattered procedures/functions, you look at organized Objects.)
You can think of a type as a simple form of class. Types can only hold variables, not procedures/functions.
An important distinction between user defined types ('UDT') and 'classes' in 'VB6' is that 'UDTs' are value types while 'classes' are reference types. This means that when you store an object ('instance' of a 'class') in a variable what actually happens is that a pointer to the existing object is stored but when you store a 'UDT' instance in a variable a copy of the instance is stored. For instance imagine that you have defined a class, 'Class1', and a UDT, 'Type1':
Dim ac As Class1 Dim bc As Class1 Dim at As Type1 Dim bt As Type1
Now assign ac to bc:
Set bc = ac
and at to bt
bt = at
Now make a change to one of the properties of bc and look at the corresponding property in ac. You should see that when you change bc that ac also changes. This is because ac and bc are really pointers to the same block of memory. If you do the same exercise with bt and at you should see that changing properties of bt does not affect at. This is because at and bt are values not references and occupy distinct locations in memory.
This is important when storing objects in 'Collections'. If you add an object to a collection you can later change the values of its properties and the object in the collection will also seem to change. in fact it is the same object because what is stored in the collection is the reference ('pointer') to the object. However if you store a 'UDT' in a collection what is stored is a copy of the values not a reference so changing the original UDT will not affect the content of the Collection.
Classes are a combination of subroutines and types. By that I mean that when you write a class it looks very much like a type but is also contains subroutines and functions.
Each class in VB6 is a distinct file, there can only be one class in a file and the class cannot be spread out in several files; this is a feature of VB6 not a requirement of object oriented programming.
A class looks very much like an ordinary module but has the file extension .cls instead of .bas
There are two types of inheritance: implementation and interface. However Visual Basic Classic provides only Interface inheritance. Implementation inheritance can be simulated by a combination of interface inheritance and delegation.
One of the common ways to introduce inheritance is to show a program that creates dog and cat objects or car and train objects.
For example in Visual Basic we can declare two classes dog and cat like this:
Option Explicit Public Sub Sound() Debug.Print "Woof" End Sub
Option Explicit Public Sub Sound() Debug.Print "Meow" End Sub
Public Sub main() Dim oDog as cDog Dim oCat as cCat Set oDog = New cDog Set oCat = New cCat oDog.Sound oCat.Sound End Sub
When you run this program it will print:
Now this is all very well until you decide that you would like an array of pets:
Dim aPets(1 to 10) as ????
Unless you declare the aPets array as variant you have to give it a type. One way is to create a class called cPet and use it instead of cDog and cCat:
Option Explicit Public IsDog as Boolean Public Sub Sound() If IsDog Then Debug.Print "Woof" Else Debug.Print "Meow" End If End Sub
Now our main routine might look like this:
Option Explicit Dim aPet(1 to 10) as cPet Public Sub main() Dim lPet as Long For lPet = 1 to 10 Set aPet(lPet) = New cPet If lPet<=5 then aPet(lPet).IsDog = True Else aPet(lPet).IsDog = False End If Next lPet ' Now find out what noise they make. For lPet = 1 to 10 aPet(lPet).Sound Next lPet End Sub
This should print:
Woof Woof Woof Woof Woof Meow Meow Meow Meow Meow
Look reasonable? For the requirements so far revealed this works fine. But what happens when you discover that there are things that cats do that have no analogue in dogs? What about other kinds of pet? For example, you want your cat to purr. You can have a method called purr but where will you put it? It surely doesn't belong in cPet because dogs can't purr and neither can guinea pigs or fish.
The thing to do is to separate out those features that are common to all pets and create a class that deals only with those, we can rewrite cPet for this purpose. Now we can go back to our original cDog and cCat classes and modify them to inherit the 'interface from cPet.
Class cPet rewrittenEdit
Option Explicit Public Sub Sound() End Sub
Notice that the Sound method is empty. this is because it exists only to define the interface. The interface is like the layout of the pins on a plug or socket; any plug that has the same layout, size and shape will plug in to a socket implementing the same interface. What goes on inside the thing you plug in is a separate issue; vacuum cleaners and television sets both use the same mains plug.
To make this work we must now modify cDog and cCat:
Option Explicit Implements cPet Private Sub cPet_Sound() Debug.Print "Woof" End Sub
Option Explicit Implements cPet Private Sub cPet_Sound() Debug.Print "Meow" End Sub Public Sub Purr() Debug.Print "Purr" End Sub
In the pet examples above an array of cPet objects is used to hold the pets. This works well if you know exactly how many pets you have. But what happens if you adopt another stray puppy or your cat has kittens?
One solution is to use a Collection object instead of an array. A collection object looks a little like an array but lets you add and remove items without worrying about the declared size, it just expands and contracts automatically.