Inheritance

Inheritance is the concept that a new class can be based on an existing class, inheriting its interface and functionality from the original class.With inheritance, a class gains all the properties and methods that make up the interface of the base class, and it can then extend the interface by adding properties and methods of its own. The new class can also extend or change the implementation of each of the properties and methods from the original base class.

For instance, if we had a class called Fruit that had all the properties and methods which apply to all types of fruit, then inheritance would make it very easy to create classes for Apple, Orange and so forth. We wouldn't have to recreate all the code for an apple to be a fruit: it would get that automatically from the original Fruit class.

Interface Inheritance

Visual Basic 5.0 doesn't directly support the concept of inheritance. It does provide something called interface inheritance using the Implements keyword. We've already used this keyword when we discussed polymorphism, but it can be applied here to help simulate a form of inheritance.

Interface inheritance lets us inherit the interface of one class into a new class. The downside is that all we get is the interface, not the original object's data or behavior. Worse still, we can't extend an interface created with the Implements keyword. One of the key benefits of inheritance is the ability to extend the base interface, so this is a substantial drawback.

If we look at a Fruit class, we'll find an interface that includes elements appropriate for any type of fruit. In this example, we've got a growing climate and color for the fruit:

Option Explicit

Public Property Get GrowingClimate() As String

End Property

Public Property Get Color() As String

End Property
Public Property Get Bites() As Integer

End Property

Notice that there's no code in the routines shown here. That's because all we'll be inheriting is the interface; any code in these routines wouldn't be used anyway.

Now we can create a new class, Apple, and inherit the interface from the Fruit class by using the Implements keyword:

Option Explicit

Implements Fruit

Private Property Get Fruit_GrowingClimate() As String
  Fruit_GrowingClimate = "Moderate"
End Property

Private Property Get Fruit_Color() As String
  Fruit_Color = "Red"
End Property

Private Property Get Fruit_Bites() As Integer
  Fruit_Bites = 20
End Property

Earlier in the chapter, we discussed multiple interfaces and how the Implements keyword works. Instead of declaring GrowingClimate, Color and Bites directly, we need to make them Private in scope and put Fruit_ in front of each name so Visual Basic knows that these routines belong to the Fruit interface.

We might also create an Orange class, again based on the Fruit interface:

Option Explicit

Implements Fruit

Private Property Get Fruit_GrowingClimate() As String
  Fruit_GrowingClimate = "Warm"
End Property

Private Property Get Fruit_Color() As String
  Fruit_Color = "Orange"
End Property

Private Property Get Fruit_Bites() As Integer
  Fruit_Bites = 20
End Property

Now, contrary to what we'd expect, we can write code to compare apples and oranges:

Public Function CompareColor(AnApple As Fruit, AnOrange As Fruit)
  CompareColor = (AnApple.Color = AnOrange.Color)
End Function

More importantly, we've created two different classes, both having inherited the same interface from Fruit. This is a very powerful technique when we have otherwise dissimilar classes that have a number of the same interface elements. We can write client code to treat all the objects the same - even though they are different.

Unfortunately, this technique doesn't allow us to extend the interface, and so it is less a way to implement inheritance than it is to implement polymorphism, as in the last section. The Orange class can't add properties or methods to its version of the Fruit interface. This limits our flexibility, and really prevents us from using this to simulate full-blown inheritance.

Containment and Delegation

Fortunately, it is possible, with a little extra work, to roll our own inheritance using Visual Basic - and thus gain many of the advantages we'd get in other languages that fully support inheritance. This is achieved by combining a concept called containment with another called delegation.

Containment is the idea that an object can have a private instance of another object inside itself. Were we to have a Human object, it might contain a Heart object. The Heart object would be private to the Human object, since no client code would normally interact with the Heart.

Delegation means that one object delegates work to another object rather than doing the work itself. If our Human object has a PulseRate property, it might ask the Heart object for the rate rather than figuring it out by itself. It has effectively delegated the responsibility for the PulseRate to the Heart object.

If we combine these two concepts, we can simulate inheritance. Let's look at how that can work with our fruit example.

Again, we'll create a class called Fruit; but this time we'll put some code in the GrowingClimate routine. With inheritance, we'd expect to be able to use this behavior in any new classes we create based on Fruit:

Option Explicit

Public Property Get GrowingClimate() As String
  GrowingClimate = "Moderate"
End Property

Public Property Get Color() As String

End Property

Public Property Get Bites() As Integer

End Property

Now we'll create an Apple class, but this time we won't use the Implements keyword. Instead, we'll manually recreate the interface from the Fruit class - with absolutely no changes to the declarations of either property:

Option Explicit

Private objFruit As New Fruit

Public Property Get GrowingClimate() As String
  GrowingClimate = objFruit.GrowingClimate
End Property

Public Property Get Color() As String
  Color = "Red"
End Property

Public Property Get Bites() As Integer
  Bites = 20
End Property

The first thing you might notice is that we're creating a Private Fruit object within our new class. Our new Apple class is using the concept of containment to have an instance of the Fruit class inside itself:

Private MyFruit As New Fruit

In the GrowingClimate routine, our new Apple class just delegates the work down to the private Fruit object:

GrowingClimate = objFruit.GrowingClimate

Now let's create an Orange class by following the same technique:

Option Explicit

Private objFruit As New Fruit

Public Property Get GrowingClimate() As String
  GrowingClimate = "Warm"
End Property

Public Property Get Color() As String
  Color = "Orange"
End Property

Public Property Get Bites() As Integer
  Bites = objFruit.Bites
End Property

Public Property Get Slices() As Integer
  Slices = Bites / 2
End Property

Since the GrowingClimate for an Orange is different, it doesn't delegate that call down to the Fruit object. Instead, it replaces, or overrides, the functionality by implementing the routine itself.

We have also extended the interface for our Orange object by adding a Slices property. While we've simulated the inheritance of the GrowingClimate, Color and Bites properties, we're also able to extend the interface as needed for each specific class.

Back to our client code, which compares apples and oranges, we need to change how we accept our parameters:

Public Function CompareColor(AnApple As Object, _
    AnOrange As Object)
  CompareColor = (AnApple.Color = AnOrange.Color)
End Function

The code within this routine is the same as we had before, but now our parameters are of type Object instead of type Fruit. Since our new classes don't use the Implements keyword, we can't have Visual Basic treat these objects like a Fruit object.

However, we do know that they have the same set of properties and methods, and so we can write our code to treat them identically. We just need to tell Visual Basic that they are generic objects rather than objects of a specific class.