[Threadsafe_]DeclareClass(<class>[,<SuperClass>[,(<Startparameter>)]])
It is easy to declare a class. Simpel create an Interface and a Structure. The Structure should have the same name as the Interface, but with a underline (_) at the start. The should EXTENDS the BaseClass (or _BaseClass) (alternativ you can add a __VT.i as first element of the structure. BaseClass contain only this entry).
With DeclareClass you finalize the declaration. (We talk about Threadsafe and Start-Parameter later)
Code: Select all
Interface Counter Extends BaseClass
Get()
Set(Value)
Add(Value=1)
EndInterface
Structure _Counter Extends _BaseClass
_Value.i
EndStructure
DeclareClass(Counter)
AllcoateObject(<Class> [,(<StartParameter>)])
FreeObject(<object>)
After the declaration you can use the class already. With AllocateObject(<Class>) or <Class>() you create a new object. FreeObject(<Object>) destroy the object.
Code: Select all
Define *test.Counter
*test=AllocateObject(Counter)
Debug "obj:"+Hex(*test)
Debug *test\Get()
*test\set(20)
Debug *test\get()
*test\add(20)
Debug *test\Get()
*test=FreeObject(*test)
The definition of a method is not so easy, there a two possibilities. First ist to use Class(<ClassName>,<Method>,<Parameter>) as Procedure Name. The first parameter of the parameter block must be *self When you want to return a string, you must use ClassS(), for double ClassD() and so on.
Code: Select all
Procedure Class(Counter,Get, (*self._counter))
ProcedureReturn *self\_Value
EndProcedure
Procedure Class(Counter,Set, (*self._counter,Value))
*self\_Value=Value
EndProcedure
Procedure Class(Counter,Add, (*self._counter,Value=1))
*self\_Value+Value
EndProcedure
The second possibility is to write a normal procedure with <class>_<method> as name and add the AsMethod() after the procedure.
Code: Select all
Procedure Counter_Add(*self._counter.Value=1)
*self\_Value+Value
EndProcedure:AsMethod(Counter,Add)
When you inherit a class, you can overwrite the method of the SuperClass (Parent).
ClassConstructor(<Class>,(<Parameter>))
ClassDestructor(<Class>,(<Parameter>))
ClassCopyConstructor(<Class>,(<Parameter>))
My routines support a constructors and destructors. You can use this three macros to use it like the Class-Macro above. Or you can use the direct procedure-names:<Class>___Constuctor(), <Class>__Destructor() and <Class>___CopyConstructor(). Important: There are three underlines! And you should not use AsMethod().
Constructors and destructors will not be overwritten, instead they are all executed. First the SuperClass (parent) Constructor then the SubClass (child) Constructor. Destructors in reverse order. Constructors must return #true otherwise the creation of the object will fail.
Code: Select all
Procedure ClassConstructor(counter, (*self._counter))
Debug "New Counter:"+Hex(*self)
Procedurereturn #True
EndProcedure
Procedure ClassDestructor(counter, (*self._counter))
Debug "Free Counter:"+Hex(*self)
EndProcedure
Procedure ClassCopyConstructor(Counter, (*self._Counter,*org._Counter))
Debug "Copy Counter:"+Hex(*self)+" from "+Hex(*org)
Procedurereturn #True
EndProcedure
After all methods are defined, you must finalize the class with this command.
One important rule: Don't define a Method of a diffrent class between the first method-definition and the final DefineClass()!
Code: Select all
DefineClass(counter)
Code: Select all
Interface CounterPlus Extends Counter
GetTimestamp()
EndInterface
Structure _CounterPlus Extends _Counter
_timestamp.i
EndStructure
DeclareClass(CounterPlus,Counter)
Procedure Class(CounterPlus,Set, (*self._CounterPlus,value));-counterplus set
*self\_Value=value
*self\_timestamp=12
EndProcedure
Procedure Class(CounterPlus,Add, (*self._CounterPlus,value))
*self\_Value+value
*self\_timestamp=1
EndProcedure
Procedure Class(CounterPlus,GetTimestamp, (*self._CounterPlus))
ProcedureReturn *self\_timestamp
EndProcedure
Procedure ClassConstructor(CounterPlus, (*self._CounterPlus))
Debug "New Counterplus:"+Hex(*self)
EndProcedure
Procedure ClassDestructor(CounterPlus, (*self._CounterPlus))
Debug "Free Counterplus:"+Hex(*self)
EndProcedure
Procedure ClassCopyConstructor(CounterPlus, (*self._CounterPlus,*org._CounterPlus))
Debug "Copy Counterplus:"+Hex(*self)+" from "+Hex(*org)
EndProcedure
DefineClass(CounterPlus)
ReferenceObject(<Object>)
Increase the reference counter of an Object. For every Reference it is necessary to call a FreeObject() to destroy the object.
Return the number of the activ references.
CountReferenceObject(<Object>)
Return the count of references of an object.
CopyObject(<Object>)
Create a copy of a object and return it. If it fails #Null.
IsClassObject(<ClassName>,<Object>)
Check if an object is part of the class. Important: A Object of a subclass (child) is always part of the SuperClass (parent).
IsObject(<Object>)
Check if an object is really a object created with this routines. IMPORTANT: To check this, the routines use a PEEKI() to the adress one Integer below the object. There is a check, if the Object ist #null.
ClassId(<Class>)
Return the ClassID of the class. (btw. this is the VTable)
ObjectId(<Object>)
Return the ClassId of an Object. When you need to know, it the class of an Object is really identical to a spezific class, compare the ClassId() with the ObjectId()
CountObject(<Class>)
Return how many object of a class exist. Useful to find memory leaks.
GetClassMethod(<class>,method.s)
Return the adress of the method or #Null.
Code: Select all
Debug "Method CounterPlus\Timestamp "+Hex(GetClassMethod(test::CounterPlus,"GetTimeStamp"))
Same as above, but from an Object.
Code: Select all
Debug "Method x4\text "+Hex(GetObjectMethod(x4,"text"))
like above, but return the index in the VTable (start with 0) or -1, if the method doesn't exist.
DeclareDebugObject()
DefineDebugObject()
DebugObject(<Object>)
You must define DebugObject with the command above, before you can use it. It output the object with it methods. Like the Debug command, without activ debugger this commands are removed complete automatically.
Code: Select all
DebugObject(x4)
DeclareGetClassNameMethod()Output wrote:OUTPUT OBJECT x4 @49B0C70 of SteuerP
Set @14000AF7C
get @140008B18
Text @1400077CD
OUTPUT END
DefineGetClassNameMethod()
GetClassNameMethod(ClassName.s,Method.s)
Work like GetClassMethod(), but this time ClassName is a String. Important: the module-name is not optional!
Code: Select all
Debug "Class test::counter get:"+Hex(GetClassNameMethod("teSt::CounTeR","Get"))
Return the name of the class of an object.
GetClassIdName(classid)
Return the name of an ClassId.
Threadsafe
When you need an object to be threadsafe, you should declare it with Threadsafe_DeclareClass() IMPORTANT: You must secure the methods by your own!
LockObject(Object) and UnlockObject(Object)
Lock the object with a mutex. You can use this two commands, even the class is not threadsafe.
You should not lock the object in the constructors and destructors.
Optional startparmater
Simple add a parameter-block in the DeclareClass() and DefineClass() command. And don't forget to add a constructor. When a SuperClass has parameter, a SubClass must have the same. When the Superclass has no parameter, a SubClass can have some!
Code: Select all
Interface Steuer Extends BaseClass
set()
get()
EndInterface
Structure _Steuer Extends _BaseClass
value.i
EndStructure
DeclareClass(Steuer,BaseClass,(StartValue))
Procedure Class(Steuer,set,(*self._steuer,value))
*self\value=value
EndProcedure
Procedure Class(Steuer,get,(*self._steuer))
ProcedureReturn *self\value
EndProcedure
Procedure ClassConstructor(Steuer,(*self._steuer,StartValue))
Debug "Steuer-Constructor "+Hex(*self)+" with Value:"+StartValue
*self\value=StartValue
ProcedureReturn #true
EndProcedure
DefineClass(Steuer,BaseClass,(StartValue),(*self,StartValue))
Code: Select all
Define x1.steuer=Steuer(10)
Debug x1\get()
Define x2.steuer=AllocateObject(Steuer,(20))
Debug x2\get()
Define x3.steuer=AllocateObject(Steuer,(30))
Debug x3\get()