Visual Basic Concepts
As explained in "How Visual Basic Provides Polymorphism," an interface is a set of properties and methods. In the following code example, you'll create an Animal interface and implement it in two classes, Flea and Tyrannosaur.
You can create the Animal interface by adding a class module to your project, naming it Animal, and inserting the following code:
Public Sub Move(ByVal Distance As Double)
End Sub
Public Sub Bite(ByVal What As Object)
End Sub
Notice that there's no code in these methods. Animal is an abstract class, containing no implementation code. An abstract class isn't meant for creating objects — its purpose is to provide the template for an interface you add to other classes. (Although, as it turns out, sometimes it's useful to implement the interface of a class that isn't abstract; this is discussed later in this topic.)
Note Properly speaking, an abstract class is one from which you can't create objects. You can always create objects from Visual Basic classes, even if they contain no code; thus they are not truly abstract.
Now you can add two more class modules, naming one of them Flea and the other Tyrannosaur. To implement the Animal interface in the Flea class, you use the Implements statement:
Option Explicit
Implements Animal
As soon as you've added this line of code, you can click the left-hand (Object) drop down in the code window. One of the entries will be Animal. When you select it, the right-hand (Procedure) drop down will show the methods of the Animal interface.
Select each method in turn, to create empty procedure templates for all the methods. The templates will have the correct arguments and data types, as defined in the Animal class. Each procedure name will have the prefix Animal_
to identify the interface.
Important An interface is like a contract. By implementing the interface, a class agrees to respond when any property or method of the interface is invoked. Therefore, you must implement all the properties and methods of an interface.
You can now add the following code to the Flea class:
Private Sub Animal_Move(ByVal Distance As Double)
' (Code to jump some number of inches omitted.)
Debug.Print "Flea moved"
End Sub
Private Sub Animal_Bite(ByVal What As Object)
' (Code to suck blood omitted.)
Debug.Print "Flea bit a " & TypeName(What)
End Sub
You may be wondering why the procedures are declared Private. If they were Public, the procedures Animal_Jump and Animal_Bite would be part of the Flea interface, and we'd be stuck in the same bind we were in originally, declaring the Critter argument As Object so it could contain either a Flea or a Tyrannosaur.
The Flea class now has two interfaces: The Animal interface you've just implemented, which has two members, and the default Flea interface, which has no members. Later in this example you'll add a member to one of the default interfaces.
You can implement the Animal interface similarly for the Tyrannosaur class:
Option Explicit
Implements Animal
Private Sub Animal_Move(ByVal Distance As Double)
' (Code to pounce some number of yards omitted.)
Debug.Print "Tyrannosaur moved"
End Sub
Private Sub Animal_Bite(ByVal What As Object)
' (Code to take a pound of flesh omitted.)
Debug.Print "Tyrannosaur bit a " & TypeName(What)
End Sub
Add the following code to the Load event of Form1:
Private Sub Form_Load()
Dim fl As Flea
Dim ty As Tyrannosaur
Dim anim As Animal
Set fl = New Flea
Set ty = New Tyrannosaur
' First give the Flea a shot.
Set anim = fl
Call anim.Bite(ty) 'Flea bites dinosaur.
' Now the Tyrannosaur gets a turn.
Set anim = ty
Call anim.Bite(fl) 'Dinosaur bites flea.
End Sub
Press F8 to step through the code. Notice the messages in the Immediate window. When the variable anim
contains a reference to the Flea, the Flea's implementation of Bite is invoked, and likewise for the Tyrannosaur.
The variable anim
can contain a reference to any object that implements the Animal interface. In fact, it can only contain references to such objects. If you attempt to assign a Form or PictureBox object to anim
, an error will occur.
The Bite method is early bound when you call it through anim
, because Visual Basic knows at compile time that whatever object is assigned to anim
will have a Bite method.
Remember the GetFood procedure from "How Visual Basic Provides Polymorphism?" You can add the second version of the GetFood procedure — the one that illustrates polymorphism — to Form1, and replace the code in the Load event with the following:
Private Sub Form_Load()
Dim fl As Flea
Dim ty As Tyrannosaur
Set fl = New Flea
Set ty = New Tyrannosaur
'Flea dines on dinosaur.
Call GetFood(fl, ty)
' And vice versa.
Call GetFood(ty, fl)
End Sub
Stepping through this code shows how an object reference that you pass to an argument of another interface type is converted into a reference to the second interface (in this case, Animal). What happens is that Visual Basic queries the object to find out whether it supports the second interface. If the object does, it returns a reference to the interface, and Visual Basic places that reference in the argument variable. If the object does not support the second interface, an error occurs.
Suppose the Move method returned a value. After all, you know how far you want an Animal to move, but an individual specimen might not be able to move that far. It might be old and decrepit, or there might be a wall in the way. The return value of the Move method could be used to tell you how far the Animal actually moved.
Public Function Move(ByVal Distance As Double) _
As Double
End Function
When you implement this method in the Tyrannosaur class, you assign the return value to the procedure name, just as you would for any other Function procedure:
Private Function Animal_Move(ByVal Distance _
As Double) As Double
Dim dblDistanceMoved As Double
' Code to calculate how far to pounce (based on
' age, state of health, and obstacles) is omitted.
' This example assumes that the result has been
' placed in the variable dblDistanceMoved.
Debug.Print "Tyrannosaur moved"; dblDistanceMoved
Animal_Move = dblDistanceMoved
End Function
To assign the return value, use the full procedure name, including the interface prefix.
For More Information The interfaces you implement can have properties as well as methods. "Implementing Properties" discusses some differences in the way properties are implemented.