INHERITANCE ISSUES:
-------------------
In oObject the ::super:<method> type of inheritance is not really used. Instead, oObject uses a technique called "method aliasing". This technique requires that every new class has its own "alias", a pseudonym that oObject
uses to internally rename parent methods and transfer them in the child classes e.g.

(1) CLASS Parent Alias oP
...
METHOD Display()
...
ENDCLASS

(2) CLASS Child ALIAS oC
...
METHOD Display()
...
ENDCLASS

In this example, class "child" has 2 ::display() methods, its own ::display() and its parent's ::oPDisplay() method. Parent methods that don't share the same name as child classes are transfered unaliased.

This technique ensures that each new class is self contained and does not really reference its parent except at creation time. Other OOP libraries keep static arrays that are scanned to find the correct parent:method. This
is not necessary in oObject since each class contains all methods it will ever need - except parent internal and local METHODS/IVARS.

This however raises another issue. Classes that carry a huge number of messages. oObject supports up to 250 Instance Variables & INLINE-BLOCK statements and unlimited PUBLIC METHODS (STATIC Methods are implemented using INLINE statements) but its up to YOU to keep your classes small and fast. Use object subclassing (an object's IVar is a reference to another object) to avoid unnecessary inheritance.

For compatibility, each class carries a reference to its parent in the ::DICT:Super IVar and in the ::Super IVar. Accessing parent classes using ::Super:<Message> is slower than using directly the ALIASed parent Method.

Also, to access ::super using ::Super:<Message> it is necessary to first initialize all the IVars that ::Super:<Message> is likely to need, namely its formal parameters, since the parent class has not been properly
initialized in the child class. ( see "TestSta*.prg" in the EXAMPLES directory )

Starting with version 2.Ab oObject also suports true inheritance of Clipper's native classes (not subclassing). Using this feature will also result in classes with too many messages. 

Note: the implementation of this technique in version 2.B ensures that native classes Methods are inherited as true PUBLIC Methods and IVars as IVars (see ooBject.prg - METHOD __SuperMethod() ).


VARIABLE ASSIGNMENT:
--------------------
You may store default values to instance variables when initializing the new class; that means between the CLASS <cClass>... and ENDCLASS statements when declaring new variables e.g.

VAR test1 AS INT // test1 is 0
VAR test2 AS FLOAT // test2 is .F.
VAR test3 AS DATE // test3 is CTOD(" / / ")
VAR test4 AS TBrowseDB() // test4 is TBrowse object
...etc...
ENDCLASS

For some types of variables, this is very important as you may (a) save several lines of initialization code from your CONSTRUCTOR method and (b) READONLY variables that must be inherited by other classes MUST have a value upon class initialization.

Note however that at some cases this feature is not only unwanted but can also produce some erroneous results, e.g. a counter that is incremented in the first instance of the class and keeps its value to the next instance, resembling the behaviour of a STATIC variable.

That is of course, if your INIT/Constructor function does not assign values
to class variables.

It's up to you to decide which IVars to initialise in the constructor
function and which not...

Especially for READONLY variables, they can be assigned new values only
from within their class and only in two ways:

a) Assign a value at class declaration, between the CREATE CLASS and
ENDCLASS commands

b) Assign a value using the @: operator, to directly modify the self array element that points to the variable (see "Direct modification of instance variables - early binding" bellow).


USER DEFINED GET/SET IVARS
~~~~~~~~~~~~~~~~~~~~~~~~~~
Every Instance variable is infact assigned and retrieved using a GET and a SET function or a combined GET/SET Function.

To use this feature you must directly reference the Self ELEMENT you want to work with from within your GET/SET function. This means you can not use the send operator (::) to assign or retrieve the value of the IVar at hand.
This would result in a "processor stack" recursion error.

You may of course reference other class IVars using the send operator,  for example.
#translate GETSET( <xVal>, <xParm> ) => ;
<xVal> := IF( xVal==NIL, <xVal>, <xVal> := <xParm>)

CLASS Test
DATA Mydata1 GETSET My1SpecialFunc // No 1 self element
DATA Mydata2 GETSET My2SpecialFunc // No 2 self element
...
ENDCLASS

FUNCTION My1SpecialFunc( xVal )
IF xVal == NIL
RETURN QSelf[1]
ELSE
QSelf()[1] := SomeFunc( xVal )
ENDIF
RETURN QSelf()[1]

FUNCTION My2SpecialFunc( xVal )
RETURN GETSET( QSelf()[2], xVal )



                                                                                                                           

Hosted by www.Geocities.ws

1