"!

ABAP object orientation - Inheritance
ABAP cheat sheet example class

"! "!

The example class explores inheritance and demonstrate a selection of the inheritance-related syntax. "! The inheritance tree consists of four example classes. The base class {@link zcl_demo_abap_oo_inheritance_1} "! includes the implementation of the classrun interface. Choose F9 in ADT to run the class.

"!

Classes of the inheritance tree:

"! "! "!

Purpose

"!

The purpose of the example and information output is to visualize and explore concepts and syntax related to "! inheritance, checking out when and how methods are called, redefining methods, abstract and final classes and methods.

"! "!

General notes on the example

"!

Many instance methods are declared in all classes to demonstrate inheritance. However, there is no meaningful implementation "! in these methods in all classes. All instance methods include the same code. The purpose of the code in the method implementations "! is to add a line to a log table (which is output to the console) with various pieces of information:

"! "!

The information retrieval is implemented in a static method in the {@link zcl_demo_abap_oo_inheritance_1} class by getting callstack "! information to determine which method in which class was called by whom. Based on the retrieved class and method names, RTTI "! is used to get detailed information about the methods.

"! "!

Notes on this class

"! "! "!

More information

"!

Find information on getting started with the example class and the "! disclaimer in the ABAP Doc comment of class {@link zcl_demo_abap_aux}.

CLASS zcl_demo_abap_oo_inheritance_1 DEFINITION PUBLIC CREATE PUBLIC . PUBLIC SECTION. "Classrun interface INTERFACES if_oo_adt_classrun. "Instance/static constructor declarations METHODS constructor. CLASS-METHODS class_constructor. "Instance method declarations METHODS meth_public_1. "Final method METHODS meth_public_1_final FINAL. "Components used for logging information about method calls TYPES: BEGIN OF s_log, method TYPE string, implemented_where TYPE string, called_from TYPE syrepid, is_inherited TYPE abap_boolean, is_redefined TYPE abap_boolean, is_final TYPE abap_boolean, visibility TYPE abap_visibility, is_static_method TYPE abap_boolean, called_at TYPE utclong, END OF s_log, t_log TYPE TABLE OF s_log WITH EMPTY KEY. CLASS-DATA log_tab TYPE t_log. CLASS-METHODS get_method_info RETURNING VALUE(info) TYPE s_log. PROTECTED SECTION. METHODS meth_protected_1. PRIVATE SECTION. METHODS meth_private_1. ENDCLASS. CLASS zcl_demo_abap_oo_inheritance_1 IMPLEMENTATION. METHOD if_oo_adt_classrun~main. out->write( |ABAP cheat sheet example: ABAP Object Orientation - Inheritance\n\n| ). "----- First level in the inheritance hierarchy ---- "Creating an instance of the class DATA(oref_super) = NEW zcl_demo_abap_oo_inheritance_1( ). "Calling methods of the class oref_super->meth_public_1( ). oref_super->meth_public_1_final( ). oref_super->meth_protected_1( ). oref_super->meth_private_1( ). "----- Second level in the inheritance hierarchy ---- "The instance creation and method calling is delegated to "a static method in the class zcl_demo_abap_oo_inheritance_2=>perform_meth_calls_2( ). "----- Third level in the inheritance hierarchy ---- "Note: The class zcl_demo_abap_oo_inheritance_3 is abstract and contains "both non-abstract and abstract instance methods. Instances of abstract "classes cannot be created. So, the following statement is not possible. "DATA(oref_3) = NEW zcl_demo_abap_oo_inheritance_3( ). "Instance components of an abstract class can be accessed via its subclasses. "zcl_demo_abap_oo_inheritance_4 inherits from zcl_demo_abap_oo_inheritance_3 and "redefines methods of zcl_demo_abap_oo_inheritance_3. Both abstract methods (which "are mandatory to implement) and non-abstract methods are redefined. To also access "the method implementations of the non-abstract instance methods of "zcl_demo_abap_oo_inheritance_3, the respective implementations of the redefined "methods in zcl_demo_abap_oo_inheritance_4 include method calls to the direct "superclass using the syntax super->meth( ).. The instance methods of "zcl_demo_abap_oo_inheritance_3 are called in the context of the static method call "via zcl_demo_abap_oo_inheritance_4 below. "----- Fourth level in the inheritance hierarchy ---- "As above, the instance creation and method calling is delegated to "a static method in the class. This method call includes method calls to "non-abstract instance methods implemented in zcl_demo_abap_oo_inheritance_3. zcl_demo_abap_oo_inheritance_4=>perform_meth_calls_4( ). "Writing the log table to the console out->write( data = log_tab name = `log_tab` ). "Excursion: Using RTTI to retrieve the name of the superclass "As this class starts an inheritance hierarchy, the superclass of this class "is the root class OBJECT. DATA(tdo_cl) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_OO_INHERITANCE_1' ) ). DATA(superclass) = tdo_cl->get_super_class_type( )->get_relative_name( ). out->write( |\n\n| ). out->write( data = superclass name = `superclass` ). ENDMETHOD. METHOD class_constructor. INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(). = CORRESPONDING #( BASE ( ) get_method_info( ) EXCEPT called_at ). ENDMETHOD. METHOD constructor. INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(). = CORRESPONDING #( BASE ( ) get_method_info( ) EXCEPT called_at ). ENDMETHOD. METHOD meth_private_1. INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(). = CORRESPONDING #( BASE ( ) get_method_info( ) EXCEPT called_at ). ENDMETHOD. METHOD meth_protected_1. INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(). = CORRESPONDING #( BASE ( ) get_method_info( ) EXCEPT called_at ). ENDMETHOD. METHOD meth_public_1. INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(). = CORRESPONDING #( BASE ( ) get_method_info( ) EXCEPT called_at ). ENDMETHOD. METHOD meth_public_1_final. INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(). = CORRESPONDING #( BASE ( ) get_method_info( ) EXCEPT called_at ). ENDMETHOD. METHOD get_method_info. "This method retrieves callstack information to determine which method in which "class was called by whom. "Based on the retrieved class and method names, RTTI is used to get detailed "information about methods (such as the visibility or whether the method is "inherited, redefined, final, and a static method). "Getting callstack information DATA(call_stack_tab) = xco_cp=>current->call_stack->full( )->from->position( 2 )->to->position( 2 )->as_text( xco_cp_call_stack=>format->adt( ) )->get_lines( )->value. IF lines( call_stack_tab ) < 2. RETURN. ENDIF. LOOP AT call_stack_tab INTO DATA(wa) TO 2. DATA(tabix) = sy-tabix. SPLIT wa AT ` ` INTO TABLE DATA(entry). DELETE entry WHERE table_line IS INITIAL. DATA(class_name) = condense( val = entry[ 1 ] to = `` ). IF tabix = 1. info-implemented_where = class_name. DATA(meth_name) = condense( val = to_upper( entry[ 2 ] ) to = `` ). info-method = meth_name. IF class_name IS NOT INITIAL AND meth_name IS NOT INITIAL. DATA(tdo_cl) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_name( class_name ) ). DATA(methods_cl) = tdo_cl->methods. DATA(meth_info) = VALUE #( methods_cl[ name = meth_name ] OPTIONAL ). IF meth_info IS NOT INITIAL. info-is_inherited = meth_info-is_inherited. info-is_redefined = meth_info-is_redefined. info-is_final = meth_info-is_final. info-visibility = meth_info-visibility. info-is_static_method = meth_info-is_class. ENDIF. ENDIF. ELSE. info-called_from = class_name. ENDIF. ENDLOOP. ENDMETHOD. ENDCLASS.