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

Reply via email to