The definition in BASIC of class modules is possible exactly like in Visual Basic.
The sophistication level of those modules is comparable with that of VB6.
Next lines illustrate their features with a few examples.
How to proceed ?
Definition of a class :
Code: Select all
Option Compatible
Option ClassModule
Option Explicit
REM -----------------------------------------------------------------------------------------------------------------------
REM --- Internal Variables ---
REM -----------------------------------------------------------------------------------------------------------------------
Private _X As Double
Private _Y As Double
REM -----------------------------------------------------------------------------------------------------------------------
REM --- CONSTRUCTORS / DESTRUCTORS ---
REM -----------------------------------------------------------------------------------------------------------------------
Private Sub Class_Initialize()
' Default point = Origin of axis
_X = 0
_Y = 0
End Sub ' Constructor
REM -----------------------------------------------------------------------------------------------------------------------
Private Sub Class_Terminate()
_X = - 4.94065645841247E-324 ' Most negative value allowed for Double variables
_Y = - 4.94065645841247E-324
end sub
REM -----------------------------------------------------------------------------------------------------------------------
REM --- CLASS GET/LET/SET PROPERTIES ---
REM -----------------------------------------------------------------------------------------------------------------------
Public Property Get X As Double
X = _X
End Property
Public Property Let X(ByVal pValue As Double)
_X = pValue
End property
REM -----------------------------------------------------------------------------------------------------------------------
Public Property Get Y As Double
Y = _Y
End Property
Public Property Let Y(ByVal pValue As Double)
_Y = pValue
End property
REM -----------------------------------------------------------------------------------------------------------------------
Public Property Get Dummy As Variant
Dummy = Null
End Property
REM -----------------------------------------------------------------------------------------------------------------------
REM --- CLASS METHODS ---
REM -----------------------------------------------------------------------------------------------------------------------
Public Sub Move(ByVal pX As Double, ByVal pY As Double)
_X = _X + pX
_Y = _Y + pY
End Sub
The statements « Option Compatible » and « Option ClassModule » heading the module determine the characteristic of the module, i.e. it is a class module. They must be present exactly in that order, otherwise the source will not pass the compilation.
A class module contains a number of Internal Variables. They are grouped before the following functions/subs and get usually the « Private » attribute. It means that the internal variable can be used only inside the module itself. « Public » meaning the opposite. Note however that this attribute is ignored in BASIC. The internal variables may be of any type, including another class. An example will be given below. It might also refer to a UNO object.
The Subs « Class_Initialize » and « Class_Terminate » are resp. the constructor and destructor of the class. The first one is executed before the first usage of a class instance, the second at its suppression (see below).
The properties are defined by the « Property Get », « Property Let » and « Property Set » routines. « Get » provides the value of the property, « Let » corresponds with a usual assignment, « Set » is there for assigning objects or complex structures to the property. Note that the value returned by « Property Get » and the argument of « Property Let » must have IDENTICAL TYPES.
Note also that the « Exit » statement gets an additional option « Exit Property ».
Methods are Subs or Functions. A Sub executes an arbitrary action and represents the most usual case of a method.
Usage of the « Point » class:
The declaration of a class instance is done by the « Dim » statement. The associated variable should be declared as an « Object ».
The « Set » statement creates the instance and executes the constructor.
Code: Select all
Dim a As Object
Set a = New Point
a.X = 4
a.Y = 1
MsgBox a._X
However one must understand that the constructor will only be executed when the execution will reach the first executable statement involving the variable « a », i.e. just before execution of the « a.X = 4 » statement. This means that for each statement between the variable declaration and its first use the interpreter will insert code to check if there is a need to trigger the constructor.
Therefore personally I will privilege the first shape.
Code: Select all
Dim a As New Point
a.X = 4
a.Y = 1
MsgBox a._X
Code: Select all
Option Compatible
Option ClassModule
Option Explicit
REM -----------------------------------------------------------------------------------------------------------------------
REM --- Internal Variables ---
REM -----------------------------------------------------------------------------------------------------------------------
Private _R As Double
Private _Center As Object
REM -----------------------------------------------------------------------------------------------------------------------
REM --- CONSTRUCTORS / DESTRUCTORS ---
REM -----------------------------------------------------------------------------------------------------------------------
Private Sub Class_Initialize()
' Default circle = Null circle at axis origin
_R = 0
Set _Center = New Point
End Sub ' Constructor
REM -----------------------------------------------------------------------------------------------------------------------
Private Sub Class_Terminate()
_R = 0
Erase _Center
End Sub
REM -----------------------------------------------------------------------------------------------------------------------
REM --- CLASS GET/LET/SET PROPERTIES ---
REM -----------------------------------------------------------------------------------------------------------------------
Property Get R As Double
R = _R
End Property
Public Property Let R(ByVal pValue As Double)
_R = pValue
End property
REM -----------------------------------------------------------------------------------------------------------------------
Public Property Get Center As Object
Set Center = _Center
End Property
Property Set Center(ByVal pValue As Object)
Set _Center = pValue
End property
REM -----------------------------------------------------------------------------------------------------------------------
Public Function Area() As Double
Area = PI() * R * R
End Function
Public Function Circumference() As Double
Circumference = 2 * PI() * R
End Function
REM -----------------------------------------------------------------------------------------------------------------------
Public Property Get Dummy As Variant
Dummy = Null
End Property
REM -----------------------------------------------------------------------------------------------------------------------
REM --- CLASS METHODS ---
REM -----------------------------------------------------------------------------------------------------------------------
Public Sub MoveHoriz(ByVal pValue) ' pValue might be negative
_Center.Move(pValue, 0)
End Sub
Public Sub MoveVert(ByVal pValue) ' pValue might be negative
_Center.Move(0, pValue)
End Sub
REM -----------------------------------------------------------------------------------------------------------------------
Public Function IntersectX() As Variant
' Return intersection points of circle with X-axis
' Substitute y = 0 in circle equation (x-Cx)2 + (y-Cy)2 = R2
' => Equation of degree 2 with unknown x
Dim a As Double, b As Double, c As Double, dDiscr As Double
a = 1
b = -2 * _Center.X
c = (_Center.X ^ 2) + (_Center.Y ^ 2) - (R ^ 2)
dDiscr = (b ^ 2) - (4 * a * c)
Dim oInterSect1 As Object, oInterSect2 As Object
Select Case True
Case dDiscr < 0 : InterSectX = Array()
Case dDiscr = 0
Set oInterSect1 = New Point
oInterSect.X = -b / (2 * a)
Set InterSectX = Array(oInterSect)
Case Else
Set oInterSect1 = New Point
Set oInterSect2 = New Point
oInterSect1.X = (-b - Sqr(dDiscr)) / (2 * a)
oInterSect2.X = (-b + Sqr(dDiscr)) / (2 * a)
InterSectX = Array(oInterSect1, oInterSect2)
End Select
End Function
One of the internal variables is an instance of class « Point ».
A function like « Area », beside the actions it potentially executes, returns additionally a value. What's the difference between « Property Get Area() » and « Public Function Area() » ? There is no difference except when the IDE debugger is involved. See below.
The destructor « Class_Terminate » contains an « Erase » statement which itself will activate the destructor of the « _Center » object which is of type « Point ».
The « MoveHoriz » and « MoveVert » methods invoke the « Move » method of the « Point » class to apply it on the internal « _Center » variable.
Examples :
- With illustration of the benefit of the « With » statement and of cascading properties in « b.Center.X » :
Code: Select all
Dim a As Object
Set a = New Point
a.X = 2
a.Y = 1
Dim b As Object
Set b = New Circle
With b
.R = 2
Set .Center = a
.MoveHoriz(2) ' Center becomes (4,1)
MsgBox "Circle centered on (" & .Center.X & "," & .Center.Y & "). Circumference = " & .Circumference
End With
Erase b
Code: Select all
Dim b As Object
Set b = New Circle
b.Center.X = 4
b.Center.Y = 1
b.R = 2
Dim vPoints As Variant, i As Integer
vPoints = b.IntersectX() ' Return an array of Points objects
For i = LBound(vPoints) To UBound(vPoints)
MsgBox vPoints(i).X
Next i
Using Xray is useless. Indeed one can't get any useful information from that (moreover very useful) tool. However no other caveat.
The behaviour of the IDE debugger requires more attention. Either the execution is suspended inside the class. In this case the internal variables (and of course any other variable in scope) of the instance are visible as usually by naming them. Or the execution is outside the class. In that case the visualisation of a class instance will go through the computation by the debugger of each property of the class to find its value ! Really super, because even a property being itself a class instance will be displayed in a tree correctly.
However this means :
- that if the computation of the property contains an error, the debugger will make the same error. That's why it is sometimes very useful to use temporarily during the debugging a « Function » instead of « Property Get »;
- that if you are in the step-by-step mode, the step-by-step will enter, under the impulse of the debugger, into the execution of each « Property Get » routine ..., which will lead rapidly and irreversibly to a crash of AOO/LibO.
The « Dummy » property has been inserted in each class module because the debugger displays in the IDE all properties except strangely the last one ... ?
In conclusion : visualising a class variable, yes, but when the computation of the properties is error-free, and, after visualisation, remove any class variable from the watched variables before continuing the execution.
Other remarks :
Above examples work in all AOO/LibO listed in my signature.
Basic supports also the « Implements » verb like in VB6. Its usage however makes, in my opinion, not much sense.
VB6 accepts also in a class module the keyword « This » to designate the current instance in execution. Additionally it allows passing the current object as argument to a function external to the module. This seems not possible in BASIC, as far as I know.
Inheritance between object classes is not supported. Moreover the « Inherits » verb is implemented in VB only in versions later than VB6.
Hoping these explanations will be helpful ...
JPL