Visual Basic Concepts

Class Modules vs. Standard Modules

Classes differ from standard modules in the way their data is stored. There's never more than one copy of a standard module's data. This means that when one part of your program changes a public variable in a standard module, and another part of your program subsequently reads that variable, it will get the same value.

Class module data, on the other hand, exists separately for each instance of the class (that is, for each object created from the class).

By the same token, data in a standard module has program scope — that is, it exists for the life of your program — while class module data for each instance of a class exists only for the lifetime of the object; it's created when the object is created, and destroyed when the object is destroyed.

Finally, variables declared Public in a standard module are visible from anywhere in your project, whereas Public variables in a class module can only be accessed if you have an object variable containing a reference to a particular instance of a class.

All of the above are also true for public procedures in standard modules and class modules. This is illustrated by the following example. You can run this code by opening a new Standard Exe project and using the Project menu to add a module and a class module.

Place the following code in Class1:

' The following is a property of Class1 objects.
Public Comment As String

' The following is a method of Class1 objects.
Public Sub ShowComment()
   MsgBox Comment, , gstrVisibleEverywhere
End Sub

Place the following code in Module1:

' Code in the standard module is global.
Public gstrVisibleEverywhere As String

Public Sub CallableAnywhere(ByVal c1 As Class1)
   ' The following line changes a global variable
   ' (property) of an instance of Class1. Only the
   ' particular object passed to this procedure is
   ' affected.
   c1.Comment = "Touched by a global function."
End Sub

Put two command buttons on Form1, and add the following code to Form1:

Private mc1First As Class1
Private mc1Second As Class1

Private Sub Form_Load()
   ' Create two instances of Class1.
   Set mc1First = New Class1
   Set mc1Second = New Class1
   gstrVisibleEverywhere = "Global string data"
End Sub

Private Sub Command1_Click()
   Call CallableAnywhere(mc1First)
   mc1First.ShowComment
End Sub

Private Sub Command2_Click()
   mc1Second.ShowComment
End Sub

Press F5 to run the project. When Form1 is loaded, it creates two instances of Class1, each having its own data. Form1 also sets the value of the global variable gstrVisibleEverywhere.

Press Command1, which calls the global procedure and passes a reference to the first Class1 object. The global procedure sets the Comment property, and Command1 then calls the ShowComment method to display the object's data.

As Figure 9.6 shows, the resulting message box demonstrates that the global procedure CallableAnywhere set the Comment property of the object that was passed to it, and that the global string is visible from within Class1.

Figure 9.6 Message box from the first Class1 object

Press Command2, which simply calls the ShowComment method of the second instance of Class1.

As Figure 9.7 shows, both objects have access to the global string variable; but the Comment property of the second object is blank, because calling the global procedure CallableAnywhere only changed the Comment property for the first object.

Figure 9.7 Message box from the second Class1 object

*Important* Avoid making the code in your classes dependent on global data — that is, public variables in standard modules. Many instances of a class can exist simultaneously, and all of these objects share the global data in your program.

Using global variables in class module code also violates the object-oriented programming concept of encapsulation, because objects created from such a class do not contain all their data.

Static Class Data

There may be occasions when you want a single data item to be shared among all objects created from a class module. This is sometimes referred to as static class data.

You cannot implement true static class data in a Visual Basic class module. However, you can simulate it by using Property procedures to set and return the value of a Public data member in a standard module, as in the following code fragment:

' Read-only property returning the application name.
Property Get CommonString() As String
   ' The variable gstrVisibleEverywhere is stored in a
   ' standard module, and declared Public.
   CommonString = gstrVisibleEverywhere
End Property

*Note* You cannot use the Static keyword for module-level variables in a class module. The Static keyword can only be used within procedures.

It's possible to simulate static class data that's not read-only by providing a corresponding Property Let procedure — or Property Set for a property that contains an object reference — to assign a new value to the standard module data member. Using global variables in this fashion violates the concept of encapsulation, however, and is not recommended.

For example, the variable gstrVisibleEverywhere can be set from anywhere in your project, even from code that doesn't belong to the class that has the CommonString property. This can lead to subtle errors in your program.

For More Information* Global data in ActiveX components requires different handling than in ordinary programs. If you have the Professional or Enterprise Edition of Visual Basic, see "Standard Modules vs. Class Modules" in "General Principles of Component Design" of Creating ActiveX Components in the *Component Tools Guide.