Try OpenEdge Now
skip to main content
Object-oriented Programming
Programming with Class-based Objects : Assigning object references
 

Assigning object references

You can freely assign one object reference data element to another if they are defined with compatible data types. The object reference elements in an assignment have compatible data types if one of the following is true:
*Both reference elements are defined as the same class or interface type (acme.myObjs.CustObj = acme.myObjs.CustObj or acme.myObjs.Interfaces.IBusObj = acme.myObjs.Interfaces.IBusObj).
*The left-hand reference element is defined as a super class of the right-hand reference element (acme.myObjs.Common.CommonObj = acme.myObjs.CustObj).
*The left-hand reference element is defined as an interface implemented by the class referenced by the right-hand element (acme.myObjs.Interfaces.IBusObj = acme.myObjs.CustObj).
This assignment always sets the left-hand object reference data element to a copy of the right-hand object reference that points to the same object, not a reference to a new copy of the object.
When you assign a subclass object reference to a super class object reference element, the new super class object reference still points to the original subclass instance, but it provides access to the object according to the definition of the super class type. Thus, if you use the super class object reference, you can only access the methods defined in that super class.
You can also assign a class object reference to an interface object reference element, where the class implements the specified interface type at any level in its class hierarchy. If you use the new interface object reference, you can only access the methods defined in the interface.
So an object reference can be copied to an object reference data element of the same type, a super type, or an interface that the referenced object implements. The converse of this rule is not true. That is, an object reference to a super class cannot be copied to a subclass object reference element unless you use the CAST function or the DYNAMIC-CAST function, and the super class reference actually points to an object originally instantiated as the specified subclass. Thus, the compiler rejects such an assignment and only allows it if an appropriate compile-time validated CAST function, or run-time validated DYNAMIC-CAST, function is provided on the right-hand side.
The following variation on the sample Main class demonstrates compatible assignment between different types of object reference variables using the sample classes. These assignments are indicated in this Main class code by the following numbered lines:
1. Assignment between identical class types (acme.myObjs.CustObj to acme.myObjs.CustObj)
2. Assignment to a super class type from one of its subclass types (acme.myObjs.CustObj to acme.myObjs.Common.CommonObj)
3. Assignment to an interface type from a class type that implements the interface (acme.myObjs.CustObj to acme.myObjs.Interfaces.IBusObj)
This is the Main class fragment with the numbered lines:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.
USING acme.myObjs.Interfaces.*.

CLASS Main:
  DEFINE PRIVATE VARIABLE cOutFile     AS CHARACTER         NO-UNDO.
  DEFINE PRIVATE VARIABLE rCommonObj   AS CLASS CommonObj   NO-UNDO.
  DEFINE PRIVATE VARIABLE rCustObj     AS CLASS CustObj     NO-UNDO.
  DEFINE PRIVATE VARIABLE rCustObj2    AS CLASS CustObj     NO-UNDO.
  DEFINE PRIVATE VARIABLE rHelperClass AS CLASS HelperClass NO-UNDO.
  DEFINE PRIVATE VARIABLE rIBusObj     AS CLASS IBusObj     NO-UNDO.

  /* First constructor instantiates a Customer object */
  CONSTRUCTOR PUBLIC Main ( ):
    ASSIGN
      /* Create an instance of the HelperClass class */
      rHelperClass = NEW HelperClass ( )

      /* Create an instance of the CustObj class */
      rCustObj     = NEW CustObj ( )
      cOutFile      = "Customers.out".
      ...
  END CONSTRUCTOR.
  ...

  /* ObjectInfo processes information about the Customer object    */
  METHOD PUBLIC VOID ObjectInfo ( ):
    /* Demonstrates passing object references as parameters      */

    rCommonObj = rCustObj. /* #2 */

    IF rCustObj:GetClass( ):TypeName = "acme.myObjs.NECustObj" THEN
      MESSAGE "Initializing reports for New England customers at"
        STRING(rCommonObj:updateTimestamp( ))
        VIEW-AS ALERT-BOX.
    ELSE
      MESSAGE "Initializing reports for all customers at"
        STRING(rCommonObj:updateTimestamp( ))
        VIEW-AS ALERT-BOX.
    ...

    /* INPUT-OUTPUT: Must be an exact match, a class to a method defined to
       take that same class type */
    rHelperClass:ListNames (INPUT-OUTPUT rCustObj).
    rCustObj:CheckCredit ( ).
    rCustObj2 = rCustObj.  /* #1 */

    /* OUTPUT: An interface is used to receive a class that implements that
       interface */
    rHelperClass:ReportOutput (OUTPUT rIBusObj).
    IF piInfoCount <> ? AND piInfoCount > 1 THEN
      rIBusObj:printObj(piInfoCount).
    ELSE
      rIBusObj:printObj( ).
    rIBusObj:logObj (cOutFile).
    rIBusObj = rCustObj.   /* #3 */
  END METHOD.
END CLASS.
Note that all of these object references, in fact, point to the same instance of an object. When the default destructor executes, garbage collection deletes the CustObj instance that all four object references point to, and all four variables then hold invalid object references.
* Object reference assignment and casting
* Using the CAST function
* Using the DYNAMIC-CAST function