ABAP Objects: Inheritance, Interfaces & Polymorphism

ABAP supports single inheritance; every class implicitly inherits from OBJECT.

21.1 Inheritance

ABAP supports single inheritance; every class implicitly inherits from OBJECT.

ABSTRACT classes can't be instantiated; abstract methods have no implementation.

FINAL classes can't be inherited from; FINAL methods can't be redefined.

Redefinition keeps the same signature (no overloading in ABAP).

CLASS lcl_shape DEFINITION ABSTRACT.
  PUBLIC SECTION.
    METHODS constructor IMPORTING iv_name TYPE string.
    METHODS area ABSTRACT RETURNING VALUE(rv_area) TYPE f.
    METHODS describe RETURNING VALUE(rv_text) TYPE string.
  PROTECTED SECTION.
    DATA mv_name TYPE string.
ENDCLASS.

CLASS lcl_shape IMPLEMENTATION.
  METHOD constructor.
    mv_name = iv_name.
  ENDMETHOD.
  METHOD describe.
    rv_text = |{ mv_name } with area { area( ) DECIMALS = 2 }|.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_circle DEFINITION INHERITING FROM lcl_shape FINAL.
  PUBLIC SECTION.
    METHODS constructor IMPORTING iv_radius TYPE f.
    METHODS area REDEFINITION.
  PRIVATE SECTION.
    DATA mv_radius TYPE f.
ENDCLASS.

CLASS lcl_circle IMPLEMENTATION.
  METHOD constructor.
    super->constructor( `Circle` ).          " must call super constructor first
    mv_radius = iv_radius.
  ENDMETHOD.
  METHOD area.
    rv_area = '3.14159265' * mv_radius ** 2.
  ENDMETHOD.
ENDCLASS.

CLASS lcl_rectangle DEFINITION INHERITING FROM lcl_shape.
  PUBLIC SECTION.
    METHODS constructor IMPORTING iv_w TYPE f iv_h TYPE f.
    METHODS area REDEFINITION.
    METHODS describe REDEFINITION.
  PRIVATE SECTION.
    DATA: mv_w
…

21.2 Polymorphism

DATA lt_shapes TYPE STANDARD TABLE OF REF TO lcl_shape WITH EMPTY KEY.
lt_shapes = VALUE #( ( NEW lcl_circle( 2 ) ) ( NEW lcl_rectangle( iv_w = 3 iv_h = 4 ) ) ).
LOOP AT lt_shapes INTO DATA(lo_shape).
  WRITE: / lo_shape->describe( ).          " dynamic binding: subclass implementation runs
ENDLOOP.

21.3 Interfaces

A class can implement many interfaces; interfaces can include other interfaces (INTERFACES lif_other. inside an interface).

Interface methods can be marked DEFAULT IGNORE / DEFAULT FAIL (7.51+) so implementers needn't implement them.

Implement partially in abstract classes with INTERFACES lif ABSTRACT METHODS m.

INTERFACE lif_printable.
  CONSTANTS gc_version TYPE i VALUE 1.
  METHODS print RETURNING VALUE(rv_text) TYPE string.
ENDINTERFACE.

INTERFACE lif_exportable.
  METHODS to_json RETURNING VALUE(rv_json) TYPE string.
ENDINTERFACE.

CLASS lcl_invoice DEFINITION.
  PUBLIC SECTION.
    INTERFACES: lif_printable, lif_exportable.
    ALIASES print FOR lif_printable~print.
ENDCLASS.

CLASS lcl_invoice IMPLEMENTATION.
  METHOD lif_printable~print.
    rv_text = `Invoice #42`.
  ENDMETHOD.
  METHOD lif_exportable~to_json.
    rv_json = `{"id":42}`.
  ENDMETHOD.
ENDCLASS.

DATA lo_printable TYPE REF TO lif_printable.
lo_printable = NEW lcl_invoice( ).             " up-cast to interface
WRITE lo_printable->print( ).

21.4 Casting

DATA lo_shape  TYPE REF TO lcl_shape.
DATA lo_circle TYPE REF TO lcl_circle.

lo_shape = NEW lcl_circle( 1 ).               " up-cast (widening): always allowed, implicit

lo_circle ?= lo_shape.                        " down-cast (narrowing), classic syntax
lo_circle = CAST #( lo_shape ).               " modern syntax

IF lo_shape IS INSTANCE OF lcl_circle.        " safe check (7.50+)
  lo_circle = CAST #( lo_shape ).
ENDIF.

TRY.
    DATA(lo_rect) = CAST lcl_rectangle( lo_shape ).
  CATCH cx_sy_move_cast_error.
    " wrong type
ENDTRY.

21.5 Abstract vs interface

| | Abstract class | Interface | |-|----------------|-----------| | Implementation code | Yes (concrete methods) | No | | Attributes | Instance/static | Constants and (discouraged) attributes | | Multiple inheritance | No (one superclass) | A class implements many | | Use when | Sharing code among related classes | Defining contracts, enabling test doubles |