Visual Basic “inheritance”

Visual Basic lacks an inheritance mechanism (definitely more of an ActiveX constraint) that is comparable with that of C++. To reuse another object’s properties in Visual Basic, you must use something else—either composition or association.

Note By the way, C++ type of inheritance is often used badly; that is, an object that inherits from other objects exports their public interfaces. The result is that top-level objects are often bloated because they are the sum of all the public interfaces of the objects they are derived from—a sort of overprivileged and overfed upper class!

Composition is the process whereby an object is made up of other objects. Inheritance is a “kinda” (is a kind of) relationship, whereas composition is a “hasa” (has a) relationship. Obviously, then, we can describe an instance of a car as something that “hasa” engine (unless it’s been removed, of course), not as a “kinda” engine. Building from this example, in Visual Basic, we exhibit composition by having a member (probably a private member) of class Car defined as being an object of class Engine.

Consider Scenario 1:

Class CCar
Private Engine As New CEngine
Somewhere Else
Dim Car As CCar        ‘ Initialize event will create “Engine.”
Car.Start              ‘ Start is a public method of CCar.

Association has to do with associating an object pointer—in Visual Basic an object variable—with an instance of an object class. Now consider Scenario 2:

Class CCar
Public Engine As CEngine
Somewhere Else
Dim Car As CCar        ‘ Initialize event will create “Engine.”
Car.Engine.Start       ‘ Start is a public method of CEngine.

The classic question given both possibilities is, of course, “Do you start the car or the engine?” (You could use a Public Engine and composition, and then you could export the engine to be started externally—but that begs the question.) I’ll let you decide between the car and the engine! In this second scenario, it’s because we don’t have inheritance that we’re having to make the whole of the engine public so that we can “push” its starter. Making the engine public, however, might be undesirable; that is, maybe you don’t want your consumers to be able to access the engine directly—maybe that kind of access would invalidate their warranty, or maybe the engine has other methods that you wouldn’t want published. To export the Start method more directly without also exposing the engine, you need Scenario 1; that is, you’d really have a Car.StartEngine method trigger Engine.Start. (This is called forwarding.) Of course, a Car must now “know” about its internal composition and export the starter—not a good situation. You could have a car simply Implement the engine, but that’s not very clean either.

Another problem with association (actually, it’s just as easy in Visual Basic to do this via composition) as compared to inheritance is that it’s easier to accidentally negate the reference to the engine. For example, maybe you have the means to change the type of engine in your car. To do this, you first destroy

Note The placing of the New keyword is not as important (semantically) in Visual Basic as it would be in, say, C++; that is, an object declared using New doesn’t change the type of the reference being declared—it’s still an object variable, not necessarily the thing itself. In other words, even though we’re implying that Dim o As New Thing and Dim o As Thing (New’ed later) are different, they are in fact the same. This sameness is an advantage because it means that an object that is composed of a New Engine can also exhibit associative behavior. If you like, the Engine object variable is simply being associated during Car construction.

the current engine by setting the current reference to Nothing. Next, you create a new engine and reset the pointer to point to it. Historically (pre-Implements), because of the typing requirements of Visual Basic, the object variable being set must be of type Object since an object variable of type CEngine1 cannot be set to point to (“hold” in Visual Basic—the same thing) an instance of CEngine2. This, of course, also means that your engine could get set to point to a form or to some other object type. If the Set Engine =New CEngine2 code never executes, maybe you encounter an error, it means that Engine now points to Nothing—which doesn’t have a starter! This is one of the problems fixed by the Implements keyword. For more information on Implements, see Visual Basic Books Online.

The Object type is effectively typeless since it is polymorphic with any other object type. You might say that it Implements everything! You can access any object type via an object variable of type Object, yet it will respond according to the type of object it is (points to—same thing) rather than to the reference you have to it. For example, o.Start, where o is of type Object, is perfectly legal if o has previously been set to point to an object of type Engine—Visual Basic doesn’t complain by saying that the class Object doesn’t support the Start method. You’re going to get the same effect with Implements. The difference is that with Implements you should never find the method missing!

Object orientation is modeling the requirements. Defining the requirements therefore dictates the object model and implementation method you’ll employ. You can build effective sets of objects in Visual Basic, but you cannot do today all of what is possible in C++. As I said earlier, Visual Basic and C++ are two different things, and you should learn to adapt to and utilize the strengths of each as appropriate.