ABAP Inheritance: INHERITING FROM, ABSTRACT and FINAL

Category
ABAP-Statements
Published
Author
Johannes

Inheritance is a central OOP concept that enables reuse and extension of classes. In ABAP, inheritance is implemented with INHERITING FROM. ABSTRACT and FINAL control extensibility.

Basic Concepts

  • Inheritance: A class (subclass) adopts properties of another (base class)
  • ABSTRACT: Classes/methods that cannot be directly instantiated/called
  • FINAL: Classes/methods that cannot be further inherited/overridden
  • REDEFINITION: Override methods from the base class in a subclass

Syntax

Inheritance

CLASS <subclass> DEFINITION
INHERITING FROM <baseclass>.

Abstract

CLASS <classname> DEFINITION ABSTRACT.
METHODS: <methodname> ABSTRACT.
ENDCLASS.

Final

CLASS <classname> DEFINITION FINAL.
METHODS: <methodname> FINAL.
ENDCLASS.

Redefinition

CLASS <subclass> DEFINITION INHERITING FROM <baseclass>.
METHODS: <methodname> REDEFINITION.
ENDCLASS.

Examples

1. Simple Inheritance

" Base class
CLASS lcl_vehicle DEFINITION.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_brand TYPE string,
get_brand RETURNING VALUE(rv_brand) TYPE string,
start.
PROTECTED SECTION.
DATA: mv_brand TYPE string.
ENDCLASS.
CLASS lcl_vehicle IMPLEMENTATION.
METHOD constructor.
mv_brand = iv_brand.
ENDMETHOD.
METHOD get_brand.
rv_brand = mv_brand.
ENDMETHOD.
METHOD start.
WRITE: / 'Vehicle starting...'.
ENDMETHOD.
ENDCLASS.
" Subclass
CLASS lcl_car DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_brand TYPE string
iv_doors TYPE i,
get_doors RETURNING VALUE(rv_doors) TYPE i.
PRIVATE SECTION.
DATA: mv_doors TYPE i.
ENDCLASS.
CLASS lcl_car IMPLEMENTATION.
METHOD constructor.
" Call base class constructor
super->constructor( iv_brand ).
mv_doors = iv_doors.
ENDMETHOD.
METHOD get_doors.
rv_doors = mv_doors.
ENDMETHOD.
ENDCLASS.
" Usage
DATA: lo_car TYPE REF TO lcl_car.
lo_car = NEW #( iv_brand = 'BMW' iv_doors = 4 ).
WRITE: / lo_car->get_brand( ). " BMW (inherited)
WRITE: / lo_car->get_doors( ). " 4 (own method)
lo_car->start( ). " Vehicle starting... (inherited)

2. Overriding Methods (REDEFINITION)

CLASS lcl_car DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_brand TYPE string
iv_doors TYPE i,
start REDEFINITION. " Override method
PRIVATE SECTION.
DATA: mv_doors TYPE i.
ENDCLASS.
CLASS lcl_car IMPLEMENTATION.
METHOD constructor.
super->constructor( iv_brand ).
mv_doors = iv_doors.
ENDMETHOD.
METHOD start.
" Own implementation
WRITE: / 'Car starting the engine...'.
" Optional: Call base class method
" super->start( ).
ENDMETHOD.
ENDCLASS.
" Usage
DATA: lo_vehicle TYPE REF TO lcl_vehicle,
lo_car TYPE REF TO lcl_car.
lo_vehicle = NEW lcl_vehicle( 'Generic' ).
lo_vehicle->start( ). " Vehicle starting...
lo_car = NEW lcl_car( iv_brand = 'BMW' iv_doors = 4 ).
lo_car->start( ). " Car starting the engine...

3. SUPER – Calling Base Class

CLASS lcl_electric_car DEFINITION INHERITING FROM lcl_car.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_brand TYPE string
iv_doors TYPE i
iv_battery TYPE i,
start REDEFINITION.
PRIVATE SECTION.
DATA: mv_battery_capacity TYPE i.
ENDCLASS.
CLASS lcl_electric_car IMPLEMENTATION.
METHOD constructor.
" Call parent class constructor
super->constructor(
iv_brand = iv_brand
iv_doors = iv_doors
).
mv_battery_capacity = iv_battery.
ENDMETHOD.
METHOD start.
WRITE: / 'Battery check...'.
WRITE: / |Capacity: { mv_battery_capacity } kWh|.
" Call base class method
super->start( ).
ENDMETHOD.
ENDCLASS.
" Usage
DATA(lo_tesla) = NEW lcl_electric_car(
iv_brand = 'Tesla'
iv_doors = 4
iv_battery = 100
).
lo_tesla->start( ).
" Output:
" Battery check...
" Capacity: 100 kWh
" Car starting the engine...

4. Abstract Classes

" Abstract class - cannot be instantiated
CLASS lcl_shape DEFINITION ABSTRACT.
PUBLIC SECTION.
" Abstract method - MUST be implemented in subclass
METHODS: calculate_area ABSTRACT
RETURNING VALUE(rv_area) TYPE f.
" Concrete method - can be inherited
METHODS: get_name RETURNING VALUE(rv_name) TYPE string.
PROTECTED SECTION.
DATA: mv_name TYPE string.
ENDCLASS.
CLASS lcl_shape IMPLEMENTATION.
METHOD get_name.
rv_name = mv_name.
ENDMETHOD.
" calculate_area has no implementation (abstract)
ENDCLASS.
" Concrete subclass: Circle
CLASS lcl_circle DEFINITION INHERITING FROM lcl_shape.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_radius TYPE f,
calculate_area REDEFINITION.
PRIVATE SECTION.
DATA: mv_radius TYPE f.
CONSTANTS: c_pi TYPE f VALUE '3.14159265'.
ENDCLASS.
CLASS lcl_circle IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
mv_name = 'Circle'.
mv_radius = iv_radius.
ENDMETHOD.
METHOD calculate_area.
rv_area = c_pi * mv_radius ** 2.
ENDMETHOD.
ENDCLASS.
" Concrete subclass: Rectangle
CLASS lcl_rectangle DEFINITION INHERITING FROM lcl_shape.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_width TYPE f
iv_height TYPE f,
calculate_area REDEFINITION.
PRIVATE SECTION.
DATA: mv_width TYPE f,
mv_height TYPE f.
ENDCLASS.
CLASS lcl_rectangle IMPLEMENTATION.
METHOD constructor.
super->constructor( ).
mv_name = 'Rectangle'.
mv_width = iv_width.
mv_height = iv_height.
ENDMETHOD.
METHOD calculate_area.
rv_area = mv_width * mv_height.
ENDMETHOD.
ENDCLASS.
" Usage
DATA: lt_shapes TYPE TABLE OF REF TO lcl_shape.
" lo_shape = NEW lcl_shape( ). " ERROR! Abstract!
APPEND NEW lcl_circle( 5 ) TO lt_shapes.
APPEND NEW lcl_rectangle( iv_width = 4 iv_height = 3 ) TO lt_shapes.
LOOP AT lt_shapes INTO DATA(lo_shape).
WRITE: / lo_shape->get_name( ), ': Area =', lo_shape->calculate_area( ).
ENDLOOP.
" Output:
" Circle: Area = 78.54
" Rectangle: Area = 12.00

5. FINAL – Preventing Inheritance

" Final class - CANNOT be inherited
CLASS lcl_singleton DEFINITION FINAL.
PUBLIC SECTION.
CLASS-METHODS: get_instance
RETURNING VALUE(ro_instance) TYPE REF TO lcl_singleton.
PRIVATE SECTION.
CLASS-DATA: go_instance TYPE REF TO lcl_singleton.
METHODS: constructor.
ENDCLASS.
CLASS lcl_singleton IMPLEMENTATION.
METHOD constructor.
" Private constructor
ENDMETHOD.
METHOD get_instance.
IF go_instance IS NOT BOUND.
go_instance = NEW #( ).
ENDIF.
ro_instance = go_instance.
ENDMETHOD.
ENDCLASS.
" This line would cause a syntax error:
" CLASS lcl_child DEFINITION INHERITING FROM lcl_singleton.
" ...
" ENDCLASS.

6. FINAL Methods

CLASS lcl_base DEFINITION.
PUBLIC SECTION.
" This method CANNOT be overridden
METHODS: critical_operation FINAL.
" This method can be overridden
METHODS: normal_operation.
ENDCLASS.
CLASS lcl_base IMPLEMENTATION.
METHOD critical_operation.
WRITE: / 'Critical operation - not changeable'.
ENDMETHOD.
METHOD normal_operation.
WRITE: / 'Normal operation'.
ENDMETHOD.
ENDCLASS.
CLASS lcl_derived DEFINITION INHERITING FROM lcl_base.
PUBLIC SECTION.
" OK: normal_operation can be redefined
METHODS: normal_operation REDEFINITION.
" ERROR: critical_operation is FINAL
" METHODS: critical_operation REDEFINITION.
ENDCLASS.
CLASS lcl_derived IMPLEMENTATION.
METHOD normal_operation.
WRITE: / 'Overridden operation'.
ENDMETHOD.
ENDCLASS.

7. PROTECTED – Access for Subclasses

CLASS lcl_account DEFINITION.
PUBLIC SECTION.
METHODS: constructor IMPORTING iv_balance TYPE p,
get_balance RETURNING VALUE(rv_balance) TYPE p,
deposit IMPORTING iv_amount TYPE p.
PROTECTED SECTION.
" Only visible to this class and subclasses
DATA: mv_balance TYPE p DECIMALS 2.
METHODS: validate_amount IMPORTING iv_amount TYPE p
RETURNING VALUE(rv_valid) TYPE abap_bool.
PRIVATE SECTION.
" Only visible to this class
DATA: mv_account_number TYPE string.
ENDCLASS.
CLASS lcl_account IMPLEMENTATION.
METHOD constructor.
mv_balance = iv_balance.
ENDMETHOD.
METHOD get_balance.
rv_balance = mv_balance.
ENDMETHOD.
METHOD deposit.
IF validate_amount( iv_amount ).
mv_balance = mv_balance + iv_amount.
ENDIF.
ENDMETHOD.
METHOD validate_amount.
rv_valid = xsdbool( iv_amount > 0 ).
ENDMETHOD.
ENDCLASS.
CLASS lcl_savings_account DEFINITION INHERITING FROM lcl_account.
PUBLIC SECTION.
METHODS: add_interest IMPORTING iv_rate TYPE p.
ENDCLASS.
CLASS lcl_savings_account IMPLEMENTATION.
METHOD add_interest.
" Access to PROTECTED mv_balance possible
DATA(lv_interest) = mv_balance * iv_rate / 100.
" Access to PROTECTED validate_amount possible
IF validate_amount( lv_interest ).
mv_balance = mv_balance + lv_interest.
ENDIF.
" ERROR: mv_account_number is PRIVATE
" mv_account_number = '123'.
ENDMETHOD.
ENDCLASS.

8. Polymorphism

" Different vehicle types
CLASS lcl_motorcycle DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS: start REDEFINITION.
ENDCLASS.
CLASS lcl_motorcycle IMPLEMENTATION.
METHOD start.
WRITE: / 'Motorcycle roaring to life...'.
ENDMETHOD.
ENDCLASS.
CLASS lcl_truck DEFINITION INHERITING FROM lcl_vehicle.
PUBLIC SECTION.
METHODS: start REDEFINITION.
ENDCLASS.
CLASS lcl_truck IMPLEMENTATION.
METHOD start.
WRITE: / 'Truck diesel starting...'.
ENDMETHOD.
ENDCLASS.
" Polymorphic usage
DATA: lt_fleet TYPE TABLE OF REF TO lcl_vehicle.
APPEND NEW lcl_car( iv_brand = 'BMW' iv_doors = 4 ) TO lt_fleet.
APPEND NEW lcl_motorcycle( 'Honda' ) TO lt_fleet.
APPEND NEW lcl_truck( 'MAN' ) TO lt_fleet.
" All vehicles start - each in its own way
LOOP AT lt_fleet INTO DATA(lo_vehicle).
lo_vehicle->start( ).
ENDLOOP.
" Output:
" Car starting the engine...
" Motorcycle roaring to life...
" Truck diesel starting...

9. Type Checking with IS INSTANCE OF

DATA: lo_vehicle TYPE REF TO lcl_vehicle.
lo_vehicle = NEW lcl_car( iv_brand = 'Audi' iv_doors = 4 ).
" Type check
IF lo_vehicle IS INSTANCE OF lcl_car.
WRITE: / 'Is a car'.
" Downcast for specific methods
DATA(lo_car) = CAST lcl_car( lo_vehicle ).
WRITE: / 'Doors:', lo_car->get_doors( ).
ENDIF.
" With CASE TYPE OF
CASE TYPE OF lo_vehicle.
WHEN TYPE lcl_car.
WRITE: / 'Car recognized'.
WHEN TYPE lcl_motorcycle.
WRITE: / 'Motorcycle recognized'.
WHEN TYPE lcl_truck.
WRITE: / 'Truck recognized'.
WHEN OTHERS.
WRITE: / 'Unknown vehicle type'.
ENDCASE.

10. Abstract Class with Template Method Pattern

CLASS lcl_report DEFINITION ABSTRACT.
PUBLIC SECTION.
" Template Method - defines the flow
METHODS: execute FINAL.
PROTECTED SECTION.
" Hook Methods - to be implemented by subclasses
METHODS: fetch_data ABSTRACT,
process_data ABSTRACT,
display_output ABSTRACT.
ENDCLASS.
CLASS lcl_report IMPLEMENTATION.
METHOD execute.
" Fixed flow, not overridable (FINAL)
WRITE: / 'Report starting...'.
fetch_data( ).
process_data( ).
display_output( ).
WRITE: / 'Report finished.'.
ENDMETHOD.
ENDCLASS.
CLASS lcl_sales_report DEFINITION INHERITING FROM lcl_report.
PROTECTED SECTION.
METHODS: fetch_data REDEFINITION,
process_data REDEFINITION,
display_output REDEFINITION.
ENDCLASS.
CLASS lcl_sales_report IMPLEMENTATION.
METHOD fetch_data.
WRITE: / ' Loading sales data...'.
ENDMETHOD.
METHOD process_data.
WRITE: / ' Calculating revenues...'.
ENDMETHOD.
METHOD display_output.
WRITE: / ' Displaying sales report.'.
ENDMETHOD.
ENDCLASS.
" Usage
DATA(lo_report) = NEW lcl_sales_report( ).
lo_report->execute( ).
" Output:
" Report starting...
" Loading sales data...
" Calculating revenues...
" Displaying sales report.
" Report finished.

Inheritance Hierarchy

lcl_vehicle (Base class)
├── lcl_car
│ │
│ └── lcl_electric_car
├── lcl_motorcycle
└── lcl_truck

Summary

ConceptKeywordDescription
InheritanceINHERITING FROMClass extends another class
OverrideREDEFINITIONRe-implement base class method
Call base classsuper->Access parent class
AbstractABSTRACTNot instantiable / must be implemented
FinalFINALNot inheritable / not overridable
ProtectedPROTECTEDVisible to class and subclasses

Important Notes / Best Practice

  • Use Inheritance for “is-a” relationships (Car is a Vehicle).
  • For “has-a” relationships, prefer Composition.
  • Use PROTECTED for attributes/methods that subclasses need.
  • Use ABSTRACT for base classes that serve only as templates.
  • Use FINAL for classes/methods that should not be modified.
  • Polymorphism enables uniform handling of different types.
  • Use super-> to call base class implementation.
  • Check types with IS INSTANCE OF before CAST.
  • Prefer INTERFACE for loose coupling.
  • Avoid deep inheritance hierarchies (max 2-3 levels).