Visual Basic Banner Exchange

August 1998

Return to Article Index

Smart Object Management using Interface Inheritance
By Jeffrey Hasan (Client Server Specialists, Inc.)


Introduction

In last month’s article we discussed object interfaces (see "Smart Object Management using Implemented Interfaces and Polymorphism", VB Online, July 1998). Recall that if you’ve ever coded a class module, then you’ve created an interface, which is defined by the object’s properties, methods and events, as coded in the class module. Interfaces allow objects to encapsulate their code and to regulate their exchange of information with the outside world. Objects are said to have a default interface, as defined by their class module, however, they can also implement interfaces that are defined in a separate class module. It is good coding practice to define interfaces (especially complex ones) in a separate class module, and then implement the interface in your new object. Keeping interface definition separate makes object management a clearer process.

We then extended our discussion to polymorphism, which refers to the situation where different objects use, or implement, the same interface. This allows us to write extremely efficient VB code, where a single procedure can manage several objects. So for example, two distinct objects may both implement a "Save" method. Although the code behind each save method may be radically different, the fact is that by exposing the same interface, we know that each object’s "Save" method expects the same arguments. We can then write a single procedure in a .BAS module to accept either object and invoke it’s "Save" method using the appropriate arguments.

This month we will take our discussion even further to the perplexing topic of "interface inheritance" which is a type of inheritance unique to VB, compared with the direct inheritance provided by languages such as C++. With direct inheritance, a child object inherits everything from the parent object, including the parent’s interface and it’s functionality. But with interface inheritance, the process is far less direct, as we will shortly demonstrate. In order to appreciate the concepts presented here, you should have a basic understanding of interfaces and how to implement them. You should also have a basic understanding of polymorphism. Read on, and as usual, prepare to impress your friends!

The Audio-Visual Objects Example Revisited

Let’s return to the audiovisual objects that we worked with previously. The TV and VCR objects share several common properties, including the manufacturer and the model number of the object. In addition, each object has unique properties. TVs, for example, have a screen size, while VCRs do not. And VCRs have 2 or 4 tape heads, while this property does not apply to TVs, which always have none. Each object and their properties are shown in the schematic below:

TV Object VCR Object
Manufacturer Manufacturer
Model Number Model Number
Screen Size Number of Heads
Description Description
In defining the interface for each object, it is apparent that the "Manufacturer", "Model Number" and "Description" properties are common to each object. The "Description" property is a read-only string that provides a summary description of the TV or VCR. Previously we coded these objects in the following 2 ways:

Inheritance using Interfaces

The moral of the story is that common functionality need, and should, only be coded once. An alternative approach to the ones discussed above, is to code the common functionality into a base class, then allow subclasses to inherit that functionality. Inheritance simply describes the ability of a child object to use a parent object’s functionality. Thus, the TV and VCR objects in the previous example are child objects to the parent "AudioVisual" object, and therefore they should inherit functionality from their parent. In this context, "functionality" can be taken to mean methods or properties, that is, a parent object can manage and hold properties for its child objects. Without further ado, let’s construct a project to illustrate inheritance using our audiovisual objects. If you have not already done so, you should read my previous article on interfaces before proceeding, since the audiovisual objects are examined in detail.

Step 1: Code the Base class

Start by opening a standard EXE, and add a new class module, which you should name "CAudioVisual". Recall that all audiovisual objects (TVs and VCRs alike) have common "Manufacturer" and "Model Number" properties. These properties need to be managed by the base class. Add the following code listing to the "CAudioVisual" class:

'Class Name:    CAudioVisual
'Author:        Jeffrey Hasan, CSSI
'Date:          July 14, 1998
'Description:   Base class for Audio-Visual objects

Option Explicit

Private m_Manufacturer As String
Private m_ModelNumber As String

Public Property Let Manufacturer(ByVal vdata As String)
    m_Manufacturer = vdata
End Property

Public Property Get Manufacturer() As String
    Manufacturer = m_Manufacturer
End Property

Public Property Let ModelNumber(ByVal vdata As String)
    m_ModelNumber = vdata
End Property

Public Property Get ModelNumber() As String
    ModelNumber = m_ModelNumber
End Property
The code listing is very straightforward: it simply defines Property Let/Get procedures for "Manufacturer" and "Model Number" properties. But there you have it, this is our base class.

Step 2: Code the Subclass

Add another class module to the project, and name it "CTV". For clarity, we will only code the TV subclass, although the VCR subclass is coded in a similar fashion. Recall that an object’s default interface refers to its unique properties and methods, which by definition are not shared by other objects. TV objects have a "Screen Size" property, which is not shared by other objects. Thus, a pair of Property Let/Get procedures for "Screen Size" will define our TV objects default interface, as shown below:
'Class Name:    CTV
'Author:        Jeffrey Hasan, CSSI
'Date:          July 14, 1998
'Description:   Defines properties for TV Audio-Visual objects
'Note:          Every property of the CAudioVisual interface must
'               be implemented or the project will not compile

Option Explicit

'Local variables to hold property value(s)
Private mvarScreenSize As Integer

'*** Default Interface ***
Public Property Let ScreenSize(ByVal vdata As Integer)
    mvarScreenSize = vdata
End Property

Public Property Get ScreenSize() As Integer
    ScreenSize = mvarScreenSize
End Property
In order to implement the base class, the subclass must explicitly create an object reference to the base class. Thus, the CTV class must assign an object variable to the CAudioVisual class. Delegation is the name given to the process whereby one object uses another by explicitly referencing it. The object references should be set in the Initialize and Terminate events for the subclass, as shown below:
'Object reference to Base class
Dim objAV As CaudioVisual

Private Sub Class_Initialize()
    Set objAV = New CAudioVisual
End Sub

Private Sub Class_Terminate()
    Set objAV = Nothing
End Sub
The last step is for the subclass to implement the interface of the base class. This sounds complicated, but isn’t when you think about it: if the subclass implements the base class’ functionality, then it must also implement its interface, so that the outside world can communicate with the subclass, just as it communicates with the base class. The code for implementing the interface is shown below:

Implements CAudioVisual

'*** Implemented Interface ***
Private Property Let CAudioVisual_Manufacturer(ByVal RHS As String)
    objAV.Manufacturer = RHS
End Property

Private Property Get CAudioVisual_Manufacturer() As String
    CAudioVisual_Manufacturer = objAV.Manufacturer
End Property

Private Property Let CAudioVisual_ModelNumber(ByVal RHS As String)
    objAV.ModelNumber = RHS
End Property

Private Property Get CAudioVisual_ModelNumber() As String
    CAudioVisual_ModelNumber = objAV.ModelNumber
End Property
So you can see that when a TV property is set, the new value is passed directly to the CAudioVisual object. In fact, the TV objects doesn’t even keep it’s own internal copy of the property value. It doesn’t need to, because the base class has assumed this responsibility. In summary, a subclass "inherits" from a base class by delegating to the base class. This is why inheritance in Visual Basic is not considered to be "true" inheritance.

The full code listing for the CTV class is shown below. Note that we have added one more property to the default interface, called "Description", which is read-only, and which reports the properties of the currently instanced TV object using a message box:

'Class Name:    CTV
'Author:        Jeffrey Hasan, CSSI
'Date:          July 14, 1998
'Description:   Defines properties for TV Audio-Visual objects
'Note:          Every property of the CAudioVisual interface must
'               be implemented or the project will not compile

Option Explicit

Implements CAudioVisual

'Object reference to Base class
Dim objAV As CAudioVisual

'Local variables to hold property value(s)
Private mvarScreenSize As Integer

Private Sub Class_Initialize()
    Set objAV = New CAudioVisual
End Sub

Private Sub Class_Terminate()
    Set objAV = Nothing
End Sub

'*** Default Interface ***
Public Property Let ScreenSize(ByVal vdata As Integer)
    mvarScreenSize = vdata
End Property

Public Property Get ScreenSize() As Integer
    ScreenSize = mvarScreenSize
End Property

'Read-only description property
Public Property Get Description() As String
    Description = "The " & CAudioVisual_Manufacturer _
        & " " & CAudioVisual_ModelNumber & " TV has a(n) " _
        & mvarScreenSize & " inch screen."
End Property

'*** Implemented Interface ***
Private Property Let CAudioVisual_Manufacturer(ByVal RHS As String)
    objAV.Manufacturer = RHS
End Property

Private Property Get CAudioVisual_Manufacturer() As String
    CAudioVisual_Manufacturer = objAV.Manufacturer
End Property

Private Property Let CAudioVisual_ModelNumber(ByVal RHS As String)
    objAV.ModelNumber = RHS
End Property

Private Property Get CAudioVisual_ModelNumber() As String
    CAudioVisual_ModelNumber = objAV.ModelNumber
End Property

Step 3: Creating the new TV object

We’re almost done: now we need to actually use our TV object, and prove to the world that interface inheritance works. Switch over to "Form1" in your project, and add the following code listing behind the form:
'Form Name:     Form1
'Author:        Jeffrey Hasan, CSSI
'Date:          July 14, 1998
'Description:   Form1 module

Option Explicit

'Object variable for the CTV subclass
Private myTV As CTV

'Object variable for the CAudioVisual Base class
Private myAV As CAudioVisual

Private Sub Form_Load()

Set myTV = New CTV

'Set TV properties via default interface
myTV.ScreenSize = 18

'Set TV properties via implemented interface
Set myAV = myTV
myAV.Manufacturer = "Panasonic"
myAV.ModelNumber = "CT-20S15R"

'Generate a description of the TV
MsgBox myTV.Description, vbExclamation, _
    "TV Description"

End Sub
Unfortunately, a major drawback of interface inheritance shows up here, namely, that the client (in this case the Form) must be aware of the implemented interface. This means that the client must declare an object reference to the "CAudioVisual" class, which defines the implemented interface. Ideally, the client should only have to reference the "CTV" class.

Now run the project, and you should see the following dialog box appear:

Conclusions

Interface inheritance can be very useful in situations where multiple objects share common functionality, since it can save greatly on the amount of code that you have to write. In addition, working with inheritance forces you to think of objects in terms of their default and implemented interfaces, which puts you well on the road to becoming a real object oriented programmer. There are drawbacks, however, namely that the client must be aware that the object it is talking to uses an implemented interface, which violates to some degree the principle of encapsulation that OOP programmers hold so dear. Future versions of Visual Basic will hopefully reengineer the process of inheritance to bring it in line with more mature languages such as C/C++.


About the Author

Copyright 1995-1998 VB Online. All rights reserved.