In addition to using the built-in classes, users can define their own classes within GPL. User defined classes are a very powerful feature that can be of assistance is organizing a GPL project. However, for programmers that are not comfortable with object oriented programming, user defined classes do not need to be used and this section can be skipped. More traditional arrays of numeric and string variables are supported in GPL and can be utilized to implement a complete application.
A user class definition begins with a Class statement and ends with an EndClass statement. A class may be defined at the top level of a file, within a module, or within another class. User-defined classes serve as a template for objects that contain arbitrary variable fields and are associated with procedures that create and modify the objects.
Class variables, procedures, and nested classes can be declared as either Public or Private. By default these items are all Private. A Private item may not be referenced outside of the class in which it is declared. A Public item may be referenced outside of a class by using the syntax: class_name.item_name or object_name.item_name.
By default, variables declared within a class are templates for fields within objects of that class. Independent copies of these variables are found in each object of the class and do not exist outside of an object. If a non-shared class variable has an initializer, that field is set to the initializer value whenever an object is created.
If a class variable is declared Shared, only a single copy of the variable exists and is accessed independently of any objects. A PublicShared variable is normally referenced by the syntax: class_name.item_name, to emphasize that it is associated with the class and not the object. A PublicShared variable may also be accessed by the syntax: object_name.item_name which results in the same single value being referenced. The second syntax example should be avoided to prevent confusing it with a non-shared variable. If a Shared class variable has an initializer clause, the initialization occurs once when the main thread starts.
An internal Sub procedure named _Init is automatically generated to perform shared variable initialization. An internal Sub procedure named _New is automatically created to perform initialization when a new object is created. Do not attempt to create procedures with these names.
Sub, Function, and Property procedures may all be members of a class. By default, procedures declared within a class are associated with an object of that class. They are invoked by the syntax: object_name.procedure_name. Within such procedures, fields and other procedures in the class may be referenced without specifying object_name as a prefix. Instead, the object that was referenced when the procedure was initially called is assumed.
If a class procedure is declared as Shared, it is not associated with any object, and may be invoked simply as class_name.procedure_name. Since there is no object associated with this procedure, it cannot reference non-shared fields or class procedures unless it explicitly includes an object_name as a prefix.
In the example below, the variable count is a field within the class cc. The procedure Main creates a new object, aa, of class cc and sets its count field to 5. When the Inc_count procedure is called, it is passed the object aa. When Inc_count executes, its references to count are actually references to the field count within the passed aa object.
Public Class cc
Public count As Integer ' Count is a field in a cc-class obj
Public Sub Increment
count = count+1 ' Inc count field in the current obj
End Sub
End Class
Sub Main()
Dim aa As New cc ' Creates a new object of class cc
Dim bb As New cc ' Creates a new object of class cc
aa.count = 5 ' Sets count field in the object aa
aa.Increment ' Calls Sub Increment for object aa
bb.count = 20 ' Sets the field count in object bb
bb.Increment ' Calls Sub Increment for object bb
Console.WriteLine(aa.count) ' Writes 6
Console.WriteLine(bb.count) ' Writes 21
End Sub
Property procedures improve readability by allowing assignment statements to call procedures that get and set data values. Reading a Property value is very similar to calling a function that returns a value. Writing a Property value looks like an assignment statement. Read-only properties cannot be written, and write-only properties cannot be read.
A Property definition must contain a get block (that begins with a Get statement and ends with an End Get statement) or a set block (that begins with a Set statement and ends with an End Set statement) or both. When a Property value is read, the get block procedure is executed. When a Property is written, the set block procedure is executed.
In the example below, the PropertySize is defined to get and set the internal field value size_in. Additionally, the Set block clips the value to make sure that size_in is always in the range 0 to 10. Since size_in is declared as Private, it cannot be changed directly from the Main procedure.
Public Class cc
Private size_in As Integer ' size_in is field in cc-class
Public Property Size As Integer
Get
Return size_in ' Simply return the field value
End Get
Set (value As Integer)
If value > 10 Then
value = 10
ElseIf value < 0 Then
value = 0
End If
size_in = value ' Set clipped value in field
End Set
End Property
End Class
Sub Main()
Dim aa As New cc ' Creates a new object of class cc
Dim ii As Integer
aa.Size = 20 ' Calls the Size Set Property
ii = aa.Size ' Calls the Size Get Property
Console.WriteLine(ii) ' Displays value 10
aa.size_in = 5 ' Invalid since size_in is Private
End Sub
When a non-shared class procedure is called, it is automatically associated with an object. This object is used implicitly whenever a non-shared procedure or field from the current class is referenced. This associated object may be accessed directly by the built-in object Me. This object always has the type of the current class. You can use the Me object when calling procedures that require an object as a parameter. If you attempt to use Me in a shared procedure, or one not associated with a class, an exception occurs.
When an object is created with a New keyword, all fields in the new object are normally set to 0 (for numeric fields), empty (for string fields), and undefined (for object fields).
If a Sub procedure named New is defined for a class, it is automatically called whenever a new object is created. The New procedure may include an argument list. There may be multiple overloaded New procedures, each with a different argument list.
For example:
Public Class cc
Public count As Integer ' Count is field in cc-class
Public Sub New
count = 25 ' Set count to 25
End Sub
Public Sub New (value As Integer)
count = value
End Sub
End Class
Sub Main()
Dim aa As New cc ' Calls first New procedure
Dim bb As New cc(15) ' Calls second New procedure
Console.WriteLine(aa.count) ' Writes 25
Console.WriteLine(bb.count) ' Writes 15
End Sub