A super class constructor can only be called (explicitly or implicitly) once from the instantiating subclass constructor as its very first action. If all immediate super class constructors are defined with parameters (there is no default constructor), it is invalid for the instantiating constructor not to call a super class constructor, either explicitly, using the SUPER statement, or implicitly through an explicit call to an overloaded constructor using the THIS-OBJECT statement whose first action is ultimately an explicit call to a super class constructor using the SUPER statement. If the super class has a default constructor, there is no need for a subclass to use the SUPER statement to explicitly invoke a super class constructor, unless the application requires it.
Note: If you later define a constructor for the super class that takes parameters, but do not also explicitly define a default constructor for the super class that does not take parameters, all subclasses then must be updated to explicitly invoke the super class’s new constructor with parameters.
This is the syntax to invoke an overloaded constructor (defined in the instantiated class) using the THIS-OBJECT statement:
Syntax
THIS-OBJECT ( [parameter[ , parameter]...] ) .
Element description for this syntax diagram follow:
[parameter[ , parameter]...]
The parameters, if any, passed to the specified constructor. For more information on the syntax of parameter, see the Parameter passing syntax reference entry in OpenEdge Development: ABL Reference.
Note: It is a compiler error to specify NO-ERROR on the THIS-OBJECT statement. Any ERROR condition raised during execution of a constructor can be handled only by the statement that instantiates a class with the NEW function. For more information, see Raising and handling error conditions.
If all immediate super class constructors are defined with parameters (there is no default super class constructor), the first statement of a constructor must either be the SUPER statement to invoke a super class constructor, or the THIS-OBJECT statement to call another constructor overloading with the current class.
Refer, again, to this sample class hierarchy:
Progress.Lang.Object <--- Top of hierarchy
acme.myObjs.Common.CommonObj
acme.myObjs.CustObj
acme.myObjs.NECustObj <--- Bottom of hierarchy
A class or procedure that uses the NEW function to instantiate acme.myObjs.NECustObj invokes the NECustObj( ) constructor. This constructor must first execute its super class constructor. As previously noted, this can be either an explicit call—with the SUPER statement as the first executable statement—or an implicit call to the CustObj( ) constructor. The acme.myObjs.CustObj class, in turn, does the same for its super class constructor in acme.myObjs.Common.CommonObj. Because acme.myObjs.Common.CommonObj is the top of the user-defined class hierarchy, it is the first user-defined constructor to execute to completion.
But before the constructor for acme.myObjs.Common.CommonObj runs, the constructor for the built-in root class, Progress.Lang.Object, is executed, which executes standard startup behavior required by the AVM to instantiate classes at run time. The constructor for the top-level user-defined class does not ever need to explicitly invoke the constructor for Progress.Lang.Object (which relies on the default). Once the top-level user-defined constructor in acme.myObjs.Common.CommonObj completes, the CustObj( ) constructor is executed to completion followed by the NECustObj( ) constructor.
Note: If a class or procedure uses the NEW function to instantiate an additional acme.myObjs.NECustObj object, the r-code for all classes in the new object’s class hierarchy is shared with the previously instantiated object, but the constructors for all classes execute again for the new object instance (possibly, with different data).
The following example adds a constructor to the sample subclass, acme.myObjs.NECustObj, described in Overriding methods within a class hierarchy. This constructor adds code to initialize the class temp-table, ttEmail, as shown:
USING acme.myObjs.*.
CLASS acme.myObjs.NECustObj INHERITS CustObj:
DEFINE PRIVATE TEMP-TABLE ttEmail NO-UNDO
FIELD RecNum AS INTEGER
FIELD Name AS CHARACTER FORMAT "X(20)"
FIELD Email AS CHARACTER FORMAT "X(20)".
CONSTRUCTOR PUBLIC NECustObj (INPUT EmailFile AS CHARACTER): /* Because there are no parameters to the super class's constructor, this constructor call is optional */ SUPER ( ). /* 8 */
/* Code to initialize ttEmail: */ . . .
END CONSTRUCTOR.
/* Override method to always get customer name and email */
METHOD PUBLIC OVERRIDE CHARACTER GetCustomerName
(INPUT piCustNum AS INTEGER):
DEFINE VARIABLE EmailName AS CHARACTER NO-UNDO.
EmailName = SUPER:GetCustomerName (piCustNum).
FIND FIRST ttEmail WHERE ttEmail.Name = EmailName NO-ERROR.
IF AVAILABLE (ttEmail) THEN
RETURN EmailName + ";" + ttEmail.Email.
ELSE
RETURN EmailName.
END METHOD.
END CLASS.
Constructors can have an access mode of PUBLIC or PROTECTED. The following example demonstrates the use of a PROTECTED constructor. The super class SuperOnly cannot be instantiated directly from outside the class hierarchy, because it does not have a PUBLIC constructor.
Class SuperOnly can only be instantiated by instantiating a class that inherits from it, such as MyPubClass:
CLASS SuperOnly:
CONSTRUCTOR PROTECTED SuperOnly ( ):
/* An attempt to use the NEW function for SuperOnly will work only from
within the class hierarchy. This constructor can only be invoked by a
subclass object's constructor. */
END CONSTRUCTOR.
END CLASS.
CLASS MyPubClass INHERITS SuperOnly:
CONSTRUCTOR PUBLIC MyPubClass ( ):
SUPER( ). /* Invoke the Protected constructor */
/* Perform operations to instantiate this class */
...
END CONSTRUCTOR.
END CLASS.