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 Harbour@harbour-project.org http://lists.harbour-project.org/mailman/listinfo/harbour