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 classCLASS 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.
" SubclassCLASS 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.
" UsageDATA: 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.
" UsageDATA: 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.
" UsageDATA(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 instantiatedCLASS 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: CircleCLASS 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: RectangleCLASS 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.
" UsageDATA: 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.005. FINAL – Preventing Inheritance
" Final class - CANNOT be inheritedCLASS 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 typesCLASS 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 usageDATA: 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 wayLOOP 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 checkIF 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 OFCASE 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.
" UsageDATA(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_truckSummary
| Concept | Keyword | Description |
|---|---|---|
| Inheritance | INHERITING FROM | Class extends another class |
| Override | REDEFINITION | Re-implement base class method |
| Call base class | super-> | Access parent class |
| Abstract | ABSTRACT | Not instantiable / must be implemented |
| Final | FINAL | Not inheritable / not overridable |
| Protected | PROTECTED | Visible 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
PROTECTEDfor attributes/methods that subclasses need. - Use
ABSTRACTfor base classes that serve only as templates. - Use
FINALfor 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 OFbeforeCAST. - Prefer
INTERFACEfor loose coupling. - Avoid deep inheritance hierarchies (max 2-3 levels).