Try OpenEdge Now
skip to main content
Object-oriented Programming
Programming with Class-based Objects : Instantiating and managing class-based objects : Calling an overloaded method or constructor
 

Calling an overloaded method or constructor

Calling an overloaded method or constructor is generally the same as invoking non-overloaded methods and constructors, by calling the method or instantiating the class using the correct number of parameters with matching data types and modes.
Note: The scope of a method (indicated by use of the STATIC option of the METHOD statement) does not participate in method overloading. This means that you cannot define both an instance method and a static method of a class with identical signatures. Otherwise, the rules for calling overloaded methods apply the same to both types of methods. However, only instance constructors can be overloaded because a class can have only one static constructor. For more information on static methods and constructors, see Definingstatic members.
The following fragment of the acme.myObjs.CustObj sample class defines two overloadings of the printObj( ) method:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.
USING acme.myObjs.Interfaces.*.

CLASS acme.myObjs.CustObj INHERITS CommonObj IMPLEMENTS IBusObj:
  ...
  DEFINE PROTECTED TEMP-TABLE ttCustomer NO-UNDO
    FIELD ...
  ...

  /* First version of printObj prints a single copy of a report */
  METHOD PUBLIC VOID printObj ( ):
    OUTPUT TO PRINTER.
    DISPLAY dtTimestamp.
    FOR EACH ttCustomer:
      DISPLAY ttCustomer.
    END.
    OUTPUT CLOSE.
    PublishOutputGenerated("One copy of report sent to printer").
  END METHOD.

  /* Second version of printObj takes an integer parameter representing the
     number of copies to print. */
  METHOD PUBLIC VOID printObj (INPUT piCopies AS INTEGER):
    DEFINE VARIABLE iCnt AS INTEGER NO-UNDO.

    OUTPUT TO PRINTER.
    IF piCopies <> 0 THEN
    DO iCnt = 1 TO ABS(piCopies):
      DISPLAY dtTimestamp.
      FOR EACH ttCustomer:
        DISPLAY ttCustomer.
      END.
    END.
    OUTPUT CLOSE.
    PublishOutputGenerated(STRING(piCopies)
                           + " copies of report sent to printer").
  END METHOD.
  ...
END CLASS.
The following fragment is a part of the Main sample class modified to invoke these printObj( ) methods depending on a condition in an IF statement:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.
USING acme.myObjs.Interfaces.*.

CLASS Main:
  DEFINE PRIVATE VARIABLE rCustObj AS CLASS CustObj NO-UNDO.
  ...

  CONSTRUCTOR PUBLIC Main ( ):
    ...
    /* Create an instance of the CustObj class */
    rCustObj = NEW CustObj ( ).    ...
  END CONSTRUCTOR.

  ...

  /* ObjectInfo processes information about the Customer object    */
  METHOD PUBLIC VOID ObjectInfo (piInfoCount AS INTEGER):
    ...

    /* 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( ).
    ...
  END METHOD.
  ...
END CLASS.
ABL matches each overload of the method according to its parameters, where the first version takes no parameters and the second takes an INTEGER input parameter, which in this case is passed the value 3.
The following fragment of the Main sample class defines two constructors:
USING acme.myObjs.*.
USING acme.myObjs.Common.*.
USING acme.myObjs.Interfaces.*.

CLASS Main:
  DEFINE PRIVATE VARIABLE cOutFile     AS CHARACTER         NO-UNDO.
  DEFINE PRIVATE VARIABLE rCustObj     AS CLASS CustObj     NO-UNDO.
  DEFINE PRIVATE VARIABLE rHelperClass AS CLASS HelperClass 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".
    /* Subscribe OutputGenerated event handler for CustObj */
    rCustObj:OutputGenerated:Subscribe(OutputGenerated_CustObjHandler).
  END CONSTRUCTOR.

  /* Second constructor takes a character parameter representing an input file
     of email addresses to instantiate a New England Customer object */
  CONSTRUCTOR PUBLIC Main (INPUT EmailFile AS CHARACTER):
    ASSIGN
      /* Create an instance of the HelperClass class */
      rHelperClass = NEW HelperClass( )

      /* Create an instance of the NECustObj class */
      rCustObj     = NEW NECustObj(EmailFile)
      cOutFile     = "NECustomers.out".

    /* Subscribe OutputGenerated event handler for NECustObj */
    rCustObj:OutputGenerated:Subscribe(OutputGenerated_NECustObjHandler).
  END CONSTRUCTOR.
  ...
END CLASS.
This is the driver procedure for the sample classes, Driver.p, which instantiates Main using each constructor:
/** This procedure drives the class example **/
DEFINE VARIABLE rClassExample AS CLASS Main NO-UNDO.

/* Run the example for all Customers */
rClassExample = NEW Main ( ).
rClassExample:ObjectInfo (0).

/* Run the example for New England Customers */
rClassExample = NEW Main ("email.txt").
rClassExample:ObjectInfo (2).
ABL matches each overload of the constructor according to its parameters, where the first version takes no parameters and the second takes a CHARACTER input parameter, which in this case is passed the filename of a text file containing E-mail addresses.
In many cases, ABL easily matches overloaded method and constructor calls to their definitions at compile time. However for some overloading scenarios, ABL can match the correct method or constructor to call only at run time, depending on the modes, data types, and values of the parameters involved. For other scenarios, ABL must weigh several valid matches against one another to determine the most appropriate method or constructor to call.
For example, ABL matches an overloaded method call at run time when a method is passed a dynamic temp-table (TABLE-HANDLE) parameter and all available overloads of that method are defined to take different static temp-table (TABLE) parameters. ABL cannot determine what method to call at compile time because the passed TABLE-HANDLE parameter has no schema associated with it to match any of the corresponding static temp-table parameters defined for the available method overloads. However, at run time, when the TABLE-HANDLE parameter is passed with an associated temp-table, ABL can examine the schema of this temp-table to determine which of the available method overloads takes a static temp-table parameter with a schema that matches the schema of the passed temp-table. If it finds a match, ABL then invokes the matching method. Otherwise, ABL raises a run-time error.
This kind of run-time matching of overloaded method or constructor calls provides a powerful mechanism, similar to polymorphism, that you can use to invoke an appropriate method or constructor that might otherwise require additional code to identify.
For more information on defining overloaded methods and constructors, see Defining overloaded methods and constructors. For more information on finer points of method and constructor overloading and how ABL handles some of the more complex overloading scenarios, see Overloaded Method and Constructor Calling Scenarios.