Hi
I need to know how Harbour Class modal simulate
this Xbase++ behavior. OR can we have this feature
in Harbour ?
Class Abstract()
============
Description
This class is "the mother of all classes" and provides a common interface
for all Xbase++ classes. The class name Abstract reveals the class's nature:
it is an abstract class that can neither be instantiated nor can it be
inherited from on the PRG code level. All Xbase++ classes, however, can take
advantage of methods and member variables available in the Abstract class.
Methods of this class can be used to obtain information about a class and
its superclasses, or are available for special purposes, such as
notifications, for example.
Class methods
Methods in this group are always executed by the class object. However, they
may be invoked via an instance object which directs a class method call to
the class object.
:classDescribe()
Reflects the class definition
:className() --> cClassName
Retrieves the name of the class an object belongs to.
:classObject() --> oClassObject
Retrieves the class object of a class.
:initClass() --> oClassObject
Method for class object initialization.
:isDerivedFrom() --> lIsDerived
Checks if an object belongs to or is derived from a particular class.
:new() --> oInstance
Creates instances of a class.
Instance methods
Methods in this group cannot be executed by a class object but only by its
instances.
:init()
Method for instance object initialization.
:eval()
Evaluates a code block.
:set/getNoIVar()
Handles access and assign operations to undefined instance variables.
:noMethod()
[pre-prerelease] Handles calls to undefined methods
:notify()
Receives notifications from DatabaseEngines
:notifyLoaded()
Handles persistency issues.
-----------------------------------
:classDescribe( [<nInfo>] ) --> aReturn
Parameters
<nInfo>
A #define constant from CLASS.CH must be used for this parameter. It
defaults to CLASS_DESCR_ALL and defines the type of information included in
the return value.
Constants for :classDescribe()
Constant Return value
CLASS_DESCR_ALL *) All available information in one array.
CLASS_DESCR_CLASSNAME Class name as character string
CLASS_DESCR_SUPERCLASSES One-dimensional array holding the
class objects of all superclasses.
CLASS_DESCR_MEMBERS 3-column array holding information
about member variables.
CLASS_DESCR_METHODS 5-column array holding information
about methods.
CLASS_DESCR_SUPERDETAILS 3-column array holding details
about superclasses.
*) default
Return
If <nInfo> is omitted or set to CLASS_DESCR_ALL, an array with four elements
is returned. They contain the information resulting from passing one of the
following constants to this method:
obj:classDescribe() --> { CLASS_DESCR_CLASSNAME , ;
CLASS_DESCR_SUPERCLASSES, ;
CLASS_DESCR_MEMBERS , ;
CLASS_DESCR_METHODS }
The elements of this array reflect the parameter profile of the function
ClassCreate().
CLASS_DESCR_CLASSNAME
The class name as character string.
CLASS_DESCR_SUPERCLASSES
One-dimensional array containing the class objects of the superclasses.
CLASS_DESCR_MEMBERS
Two-dimensional array with three columns. It holds information about
member variables of the class. Each column can be accessed using the
following #define constants:
Constants for the member-variable array
Constant Description
CLASS_MEMBER_NAME Character string representing the name of
a single member variable
CLASS_MEMBER_ATTR Member variable attributes as numeric
CLASS_MEMBER_TYPE Reserved
CLASS_DESCR_METHODS
Two-dimensional array with five columns. It holds information about
methods of the class. Each column can be accessed using the following define
constants:
Constants for the method array
Constant Description
CLASS_METHOD_NAME Character string with the name of the method
CLASS_METHOD_ATTR Method attributes as numeric
CLASS_METHOD_BLOCK Method code block, if the method was dynamically
created with ClassCreate()
CLASS_METHOD_VARNAME The name of the redirected variable if it is
an ACCESS|ASSIGN method
CLASS_METHOD_TYPE Reserved
CLASS_DESCR_SUPERDETAILS
Two-dimensional array with three columns. It holds detailed information
about the superclasses of the class. Note that this array is not included in
the CLASS_DESCR_ALL array. It is only returned when CLASS_DESCR_SUPERDETAILS
is passed to :classDescribe() .
Constants for the superclass details array
Constant Description
CLASS_SUPERCLASS_NAME Character string representing the name of
the superclass.
CLASS_SUPERCLASS_ATTR Class attributes
CLASS_SUPERCLASS_TYPE Reserved
Description
The generic method :classDescribe() is used to inspect the structure of a
class and its superclasses at runtime. Individual information about member
variables, methods or superclasses can be obtained by passing the
corresponding #define constants to this method. If :classDescribe() is
called without a parameter, the returned array reflects the parameter
profile of the ClassCreate() function. This allows for easy creation or
modification of the structure of dynamic classes.
Example
// Inspecting an unknown object
// The following code demonstrates how to obtain information about
// the structure of a class and how to retrieve values contained in
// member variables of an unknown object.
#include "Class.ch"
PROCEDURE Main
LOCAL oXbp
oXbp := XbpDialog():new( AppDesktop(),, {10,10}, {200,200} )
oXbp:create()
SET ALTERNATE TO Dialog.txt
SET ALTERNATE ON
InspectObject( oXbp )
RETURN
PROCEDURE InspectObject( obj )
STATIC saObj := {}
LOCAL aIVars, i, imax, xVal, cType
? Replicate( "*", 40 )
? obj:className()
? Replicate( "*", 40 )
AAdd( saObj, obj )
aIVars := obj:classDescribe( CLASS_DESCR_MEMBERS )
imax := Len( aIvars )
ASort( aIVars ,,,{|x,y| Upper( x[CLASS_MEMBER_NAME] ) < ;
Upper( y[CLASS_MEMBER_NAME] ) } )
FOR i:=1 TO imax
? aIvars[i, CLASS_MEMBER_NAME], "= "
IF aIVars[i, CLASS_MEMBER_ATTR] == VAR_ASSIGN_HIDDEN
?? "HIDDEN"
LOOP
ENDIF
IF aIVars[i, CLASS_MEMBER_ATTR] == VAR_ASSIGN_PROTECTED
?? "PROTECTED"
LOOP
ENDIF
// Obtain value of exported member variable via
// symbolic name and macro operator
xVal := obj:&( aIvars[i, CLASS_MEMBER_NAME] )
cType := Valtype( xVal )
DO CASE
CASE cType == "O"
IF AScan( saObj, xVal ) == 0
// Avoid recursion for objects already inspected
AAdd( saObj, xVal )
InspectObject( xVal )
ASize( saObj, Len( saObj ) - 1 )
ELSE
QQOut( Var2Char(xVal) )
ENDIF
CASE cType == "A"
AEval( xVal, {|x| IIF( Valtype(x) == "O" , ;
InspectObject( x ) , ;
QQOut( Var2Char(x) ) ;
) } )
OTHERWISE
QQOut( Var2Char(xVal) )
ENDCASE
NEXT
RETURN
:className() --> cClassName
The method returns a character string representing the name of a class.
Description
The name of a class is identical with the name of its class function. The
class function, in turn, results from the CLASS declaration.
:classObject() --> oClassObject
The method returns the class object of a class.
Description
The class object exists only once per class. It is usually obtained by
calling the class function and creates instance objects with its :new()
method. Two instances belong to the same class, when :classObject() returns
the same object for both.
CLASS METHOD initClass
Implementation
CLASS METHOD <classname>:initClass( [<paramList,...>] )
RETURN self
<classname>
The name of the class for which the method is implemented
<paramList>
The parameters passed to the class function are also passed to :initClass()
.
Return
The method returns the class object of a class.
Description
The class method :initClass() can optionally be declared within the class
declaration (between the CLASS...ENDCLASS statements). When it is declared,
it is executed immediately after the first call to the class function, as
soon as the class object has been generated. It can be used to initialize
class variables with default values and must be programmed separately. The
arguments passed to the class function are passed to the method :initClass()
. The class object can be referenced within the source code of :initClass()
via the variable self .
Note: if :initClass() is not declared in a subclass, the :initClass() method
of the superclass is implicitly executed when the class object of the
subclass is created. When :initClass() is declared and implemented, the
:initClass() method of the super class must be called explicitly.
Example
// Initializing a class object
// The example illustrates the procedure for the initialization
// of class variables. The class method :initClass() is first
// declared and then programmed.
CLASS WindowManager
CLASS VAR aStack, nCurWin
EXPORTED:
CLASS METHOD initClass // Declares method
ENDCLASS
CLASS METHOD WindowManager:initClass // Source code for method
::aStack := {} // Initializes
::nCurWin := 0
RETURN self // class variables
:isDerivedFrom( <cClassName>|<oClassObject> ) --> lIsDerived
Parameters
<cClassName>
A character string containing the name of the class an object belongs to or
is derived from.
<oClassObject>
Alternatively, the class object can be passed instead of the class name.
Return
The method returns .T. (true) if the object executing the method belongs to
or is derived from the specified class.
Description
This method is used to check if an unknown object has features of a known
class. This is especially useful for event driven programming or when
classes are inherited from other classes.
Example
//
// This code outlines an example how to react to a specific
// event. In this case, the Return key is processed for
// a pushbutton.
nEvent := AppEvent( @mp1, @mp2, @oXbp )
IF nEvent == xbeP_Keyboard .AND. ;
mp1 == xbeK_RETURN .AND. ;
oXbp:isDerivedFrom( "XbpPushbutton" )
PostAppEvent( xbeP_Activate, NIL, NIL, oXbp )
ELSE
oXbp:handleEvent( nEvent, mp1, mp2 )
ENDIF
<ClassFunction>():new( [<paramList,...>] ) --> oInstance
<ClassFunction>
The class function is usually called to retrieve the class object before
:new() is executed.
<paramList>
The parameters passed to the :new() method are also passed to :init() .
Return
The method returns a new instance of a class.
Description
:new() is the only method of a class object that creates new objects, or
instances, of that class. This method cannot be overloaded. Immediately
after the class object has created the instance, it calls the :init() method
of the new object and passes the received parameters on to :init() .
METHOD init
Implementation
METHOD <classname>:init( [<paramList,...>] )
RETURN self
<classname>
The name of the class for which the method is implemented
<paramList>
The parameters passed to the :new() method are also passed to :init() .
Return
The method returns the object executing the method.
Description
The method :init() can optionally be declared within the class declaration
(between the CLASS...ENDCLASS statements). If it is declared, it is executed
immediately after calling the class method :new() , i.e. as soon as a new
instance of the class (the new object) is created. The method is used to
initialize instance variables of the object with default values. If :init()
is declared, it must be implemented for the class. The same arguments are
passed to the instance method :init() as to the class method :new() . Within
the source code of the method :init() , the object can be referenced through
the variable self . The operator :: can also be used (as an abbreviation for
self: ) to send a message to the object.
When a class is derived from other classes (superclasses), and the
superclasses have their own :init() methods, the :init() method of each such
superclass must be explicitly called from within the subclass :init(): , by
using the superclasses name. However, if :init() is not declared in a
subclass, the :init() method of the superclass is implicitly executed when
an object of the subclass is created.
Example
// :init() method implementation
// The example illustrates the general procedure for the
// initialization of instances.
CLASS classA // Class declaration
EXPORTED:
VAR varA1, varA2
METHOD init // Declares method :init()
ENDCLASS
METHOD init( n1, n2 ) // Implements the method
::varA1 := n1 // Assigns default values
::varA2 := n2 // to the instance variables
RETURN self
// In this procedure an object of the class classA is produced
// once without and then with arguments for the
// initialization of the object.
PROCEDURE Test
LOCAL oVar
oVar := classA():new() // No arguments with :new()
? oVar:varA1 // result: NIL
? oVar:varA2 // result: NIL
oVar := classA():new( 10, 20 ) // Default values as arguments
? oVar:varA1 // result: 10
? oVar:varA2 // result: 20
RETURN
self:eval( <bBlock>, [<ExpressionList,...>]) --> xLastValue
Parameters
<bBlock>
<bBlock> is a codeblock whose program code is executed.
<ExpressionList,...>
<ExpressionList,...> is a list of expressions whose values are passed to the
code block as parameters.
Return
The return value of :eval() is the value of the last expression in the
program code of <bBlock> . :eval() can thus return a value with any data
type.
Description
The :eval() method has the PROTECTED: attribute which means that it can only
be called within methods of a class. It is used in the same way as the
Eval() function, i.e. method and function evaluate a code block and pass
parameters on to it. The difference between Eval() function and :eval()
method lies in the accessibility of member variables within the code block.
If member variables are declared with the HIDDEN: or PROTECTED: attribute,
they cannot be accessed in a code block when it is executed using the Eval()
function. This results from the fact that the function provides no method
context when it evaluates the code block. In contrast, the method context
stays intact when a code block is passed to the :eval() method. This way,
the accessibility of hidden or protected member variables within the code
block follows the same rules as for accessing member variables in methods of
the class.
Example
// Accessing a HIDDEN variable in a code block
// The example demonstrates the difference between
// the :eval() method and the Eval() function.
// Accessing a HIDDEN variable within a code block is
// only possible with the method, not with the function.
PROCEDURE Main
LOCAL obj := Test():new()
obj:show()
RETURN
CLASS Test
HIDDEN:
VAR cText
EXPORTED:
VAR bBlock
METHOD init, show
ENDCLASS
METHOD Test:init()
::cText := "I am a HIDDEN member variable"
::bBlock := {|o| QOut( o:cText ) }
RETURN self
METHOD Test:show()
::eval( ::bBlock, self ) // This works since the method
// context stays intact
Eval( ::bBlock , self ) // This fails since the code block
RETURN // is executed in a function, not
// in a method. There is no method
// context for the code block.
:setNoIVar( <cMessage>, <xValue> )
:getNoIVar( <cMessage> ) --> xReturn
Parameters
<cMessage>
The message send to the object.
<xValue>
The value of an assignment.
Return
The return value of the method :getNoIvar() will be interpreted as the
instance variable's value. The return value of the method :setNoIvar() is
ignored.
Description
If a message is sent to an object for which no corresponding instance
variable exist, a runtime error would be generated. This runtime error is
not raised if :setNoIvar() and :getNoIVar() methods are defined. The
:getNoIvar( <cMessage> ) method handles read-access to the member variable
<cMessage>, while the :setNoIvar( <cMessage> , <xValue>) method handles
write-access. If :setNoIVar() is implemented, :getNoIVar() has to be
implemented too otherwise pre/post increment and inline assignment
operations will fail.
Both methods receive as their first parameter the message sent to the
object. These methods can be used to simulate non-existing variables, or to
implement other class-local error handling for this specific error.
Example
// setNoIvar()/getNoIVar()
// The sample illustrates the behaviour of :setNoIVar()
// and :getNoIvar() methods under different usage
// patterns.
PROCEDURE Main()
LOCAL oRW := OReadWrite():New()
// read operation
? oRW:NonExistent
// write operation (assignment)
oRW:NonExistent := 10
// Post Increment
oRW:NonExistent++
// call of a function passing a non
// existing IVar by reference
MyFunc( @oRW:NonExistent )
RETURN
// Class illustrating NoIvar handling by
// simple dumping out message name and
// the optional assignment value.
//
CLASS OReadWrite
EXPORTED:
METHOD GetNoIVar(cMessage)
METHOD SetNoIVar(cMessage,xval)
ENDCLASS
METHOD OReadWrite:GetNoIVar(cMessage)
? ::ClassName(),"::GetNoIVar(",cMessage,")"
RETURN(5)
METHOD OReadWrite:SetNoIVar(cMessage,xValue)
? ::ClassName(),"::SetNoIVar(",cMessage,",", xValue , ")"
RETURN
// function is not aware if a local var, a
// member variable or even a member variable
// which is simulated using set/getNoIVar()
// is passed in.
FUNCTION MyFunc(xVal)
? xVal
xVal := 100
RETURN
:noMethod( cMessage, [<xValue>,...] ) --> xReturn
Parameters
<cMessage>
The message send to the object.
<xValue>
The parameters passed by the callee to the undefined method.
Return
The return value will be interpreted as the return value of the called
undefined method.
Description
If an undefined method is called, a runtime error is raised. However, when
:noMethod() is declared in the class, the runtime error will not occur.
Instead, program execution is directed to this method. The parameter
<cMessage> contains the name of the undefined method, followed by the
parameters the callee has passed to the method call.
Example
// noMethod()
// The sample illustrates how :noMethod()
// behaves and does handle passed parameters.
PROCEDURE Main
LOCAL oH := OHandler():New()
? oH:Foo()
? oH:FooWithParameter("One","Two",3)
RETURN
// Simple class which redirects any unknown
// method access to the ::NoMethod()
// implementation.
CLASS OHandler
EXPORTED:
METHOD NoMethod
ENDCLASS
METHOD OHandler:NoMethod(cMessage,p1,p2)
LOCAL n
? ::ClassName(),"::NoMethod(",cMessage
FOR n:=2 TO PCount()
?? ",",PValue(n)
NEXT
?? " )"
RETURN(PCount())
METHOD notify
Implementation
METHOD <classname>:notify( <nEvent>, <nNotification> )
RETURN self
Parameters
<classname>
The name of the class for which the method is implemented.
<nEvent>
This parameter receives a numeric value that corresponds with a #define
constant listed in APPEVENT.CH. Database Engines pass xbeDBO_Notify for
<nEvent> .
<nNotification>
The second parameter identifies the situation for which an object is
notified. The file DMLB.CH lists #define constants that can be used to test
in a program which situation occurred.
Constants for identifying database operations
Constant Description
DBO_CLOSE_REQUEST File in work area will be closed
DBO_BULK_REQUEST Time consuming database operation begins
DBO_BULK_COMPLETE Time consuming database operation ends
DBO_CHANGE_ORDER Order of records changed (logical or
physical order)
DBO_TABLE_UPDATE Data in current record modified
DBO_TABLE_DELETED Record deleted
DBO_TABLE_APPEND New record created
DBO_MOVE_PROLOG Record pointer will be moved
DBO_MOVE_DONE Movement of record pointer ends
DBO_GOTOP Record pointer set to beginning of file
DBO_GOBOTTOM Record pointer set to the end of file
Return
The return value of :notify() is ignored.
Description
The method :notify() is used in conjunction with DbRegisterClient() which
registers objects as notification recipients in a used work area. Database
Engines then call the :notify() method for all registered objects when the
state in the corresponding work area changes. This can be induced by record
pointer movement or by changing data in the work area. When :notify() is
called, the work area is current in which the object is registered.
Example
// Receiving notifications from Database Engines
// The example outlines the steps necessary for receiving
// database notifications. A class is implemented with
// the method :notify() and an object of that class is
// registered in two work areas.
#include "Appevent.ch"
#include "Dmlb.ch"
PROCEDURE Main
LOCAL obj := Test():new()
USE Customer
DbRegisterClient( obj )
USE Orders NEW
DbRegisterClient( obj )
Customer->(DbSkip())
Orders->(DbSkip())
CLOSE ALL
RETURN
CLASS Test
EXPORTED:
METHOD notify
ENDCLASS
METHOD Test:notify( nEvent, nNotify )
IF nEvent <> xbeDBO_Notify
RETURN self
ENDIF
DO CASE
CASE nNotify == DBO_CLOSE_REQUEST
? Alias(), "Database will be closed"
CASE nNotify == DBO_MOVE_PROLOG
? Alias(), "About to move record pointer"
CASE nNotify == DBO_MOVE_DONE
? Alias(), "Navigation is complete"
ENDCASE
RETURN self
METHOD notifyLoaded
Implementation
METHOD <classname>:notifyLoaded()
RETURN self
Parameters
<classname>
The name of the class for which the method is implemented.
Return
The return value of :notifyLoaded() is ignored.
Description
The method is used when objects are made persistent and transformed back to
the Object data type. Objects become persistent when they are stored in a
file by the SAVE command or by transforming them into a binary string with
the Var2Bin() function. If an object is loaded back to memory using RESTORE
or Bin2Var(), the :notifyLoaded() method is executed when it is implemented
in a class. The task of this method is to restore all data required by an
object that cannot be saved in a file. This applies to all member variables
of a class having the NOSAVE attribute or to system resources that must be
requested from the operating system, such as a window handle, for example.
Example
// Making a window persistent
// The example outlines a scenario that allows for storing
// user-defined window objects to disk. The window class is
// derived from XbpDialog and holds data in member variables
// that is required for restoring the object. This information
// is retrieved within :fetchData(). The window object is created,
// destroyed and rebuilt with Bin2Var(). The :notifyLoaded() method
// requests system resources by calling the superclass's
// :init() and :create() methods.
PROCEDURE AppSys()
RETURN
PROCEDURE Main
LOCAL oXbp, cData
oXbp := TestWin():new( AppDeskTop(), , {50,50}, {600,400} )
oXbp:create()
MsgBox( "Window created" )
oXbp:fetchData()
cData := Var2Bin( oXbp )
oXbp:destroy()
oXbp := NIL
MsgBox( "Window destroyed" )
oXbp := Bin2Var( cData )
RETURN
CLASS TestWin FROM XbpDialog
EXPORTED:
VAR aPos, aSize
METHOD fetchData, notifyLoaded
ENDCLASS
METHOD TestWin:fetchData()
::aPos := ::currentPos()
::aSize := ::currentSize()
RETURN self
METHOD TestWin:notifyLoaded()
::XbpDialog:init( AppDeskTop(), , ::aPos, ::aSize )
::XbpDialog:create()
MsgBox( "Window rebuilt", ":notifyLoaded()" )
RETURN self
---------------------------------
Regards
Pritpal Bedi
--
View this message in context:
http://www.nabble.com/Xbase%2B%2B-Abstract%28%29-Class-tp22550533p22550533.html
Sent from the Harbour - Dev mailing list archive at Nabble.com.
_______________________________________________
Harbour mailing list
[email protected]
http://lists.harbour-project.org/mailman/listinfo/harbour