This topic completes the code example begun in "Creating and Implementing an Interface," and continued in "Implementing Properties." You may find it helpful to read those topics before beginning this one.
The Tyrannosaur and Flea code example seems to play fast and loose with interfaces and objects. References to objects are assigned to one object variable, and references to interfaces to another.
In fact, all of the references are object references. A reference to an interface is also a reference to the object that implements the interface. Furthermore, an object may have multiple interfaces, but it's still the same object underneath.
In Visual Basic, each class has a default interface that has the same name as the class. Well, almost the same. By convention, an underscore is prefixed to the class name. The underscore indicates that this interface is hidden in the type library.
Thus the Tyrannosaur class has a default interface called _Tyrannosaur. Because Tyrannosaur also implements Animal, the class has a second interface named Animal.
However, underneath it all, the object is still a Tyrannosaur. Place a command button on Form1, and add the following code:
Private Sub Command1_Click()
Dim ty As Tyrannosaur
Dim anim As Animal
Set ty = New Tyrannosaur
Set anim = ty
MsgBox TypeName(anim)
End Sub
You might expect the message box to display "Animal," but in fact it displays "Tyrannosaur."
When you assign a Tyrannosaur object to variable of type Animal
, Visual Basic asks the Tyrannosaur object if it supports the Animal interface. (The method used for this is called QueryInterface, or QI for short; you may sometimes hear QI used as a verb.) If the answer is no, an error occurs.
If the answer is yes, the object is assigned to the variable. Only the methods and properties of the Animal interface can be accessed through this variable.
What happens if you assign the object reference to a generic object variable, as in the following code?
Private Sub Command1_Click()
Dim ty As Tyrannosaur
Dim anim As Animal
Dim obj As Object
Set ty = New Tyrannosaur
Set anim = ty
Set obj = anim
MsgBox TypeName(obj)
End Sub
The result is again Tyrannosaur. Now, what interface do you get when you call properties and methods through the variable obj
? Add the following method to the Tyrannosaur class:
Public Sub Growl()
Debug.Print "Rrrrrr"
End Sub
The Growl method belongs to the Tyrannosaur object's default interface. In the code for the command button's Click event, replace the MsgBox statement with the following two lines of code:
obj.Move 42
obj.Growl
When you run the project and click the button, execution stops on the Growl method, with the error "Object does not support this property or method." Clearly, the interface is still Animal.
This is something to bear in mind when using variables of type Object with objects that have multiple interfaces. The interface the variable will access is the last interface assigned. For example:
Private Sub Command1_Click()
Dim ty As Tyrannosaur
Dim anim As Animal
Dim obj As Object
Set ty = New Tyrannosaur
Set anim = ty
Set obj = anim
obj.Move 42 ' Succeeds
obj.Growl ' Fails
Set obj = ty
obj.Move 42 ' Fails
obj.Growl ' Succeeds
End Sub
Fortunately, there's very little reason to use the slower, late-bound Object data type with objects that have multiple interfaces. One of the main reasons for using multiple interfaces is to gain the advantage of early binding through polymorphism.
Visual Basic class modules are not your only source of interfaces to implement. You can implement any interface contained in a type library, as long as that interface supports Automation.
If you have the Professional or Enterprise Edition of Visual Basic, you can create your own type libraries of abstract classes. These type libraries can be used in many projects, as described in "General Principles of Component Design" in Creating ActiveX Components in the Component Tools Guide.
The Professional and Enterprise editions also include the MkTypLib (Make Type Library) utility in the Tools directory. If you've used this utility with Microsoft Visual C++, you may find it a more congenial way to create interfaces.
To use an interface in your project, click References on the Project menu to open the References dialog box. If the type library is registered, it will appear in the list of references, and you can check it. If the type library is not in the list, you can use the Browse button to locate it.
Once you have a reference to a type library, you can use Implements to implement any Automation interfaces the type library contains.
For More Information You're not limited to implementing abstract interfaces. "The Many (Inter)Faces of Code Reuse" describes how you can implement an interface and selectively reuse the properties and methods of the class that provides the interface.