Using Inheritance

Objectives

After completing this lesson, you will be able to:

  • Use inheritence

Subclass Instantiation

To instantiate a subclass, you declare a reference variable with the type of the relevant class. Then you use the NEW operator to create the instance. You must pass values to all obligatory parameters of the constructor.

Using Superclass References

A reference variable with the type of a superclass (in this case lcl_plane) can also hold references to objects with the type of a subclass. This makes sense, since a passenger plane or a cargo plane is a plane.

However, a reference variable with the type of the superclass is only aware of the components defined in the superclass. Consequently, when you use a reference with this type to manage an instance of a subclass, you can only address the components from the superclass, even though the actual object to which the reference points is an instance of the subclass.

Assigning object references to a reference variable of a different type is called casting. Assigning a reference that points to a subclass to a reference variable with the type of a superclass is called an up-cast, because you are making the assignment to a type higher up in the inheritance hierarchy.

Calling Methods After an Up-Cast

When you use a reference variable with type ref to lcl_plane to manage a passenger plane instance, you cannot use it to access components that belong to the passenger plane class, as the plane class does not know that they exist and the syntax check cannot know what type of object the reference will actually point to at runtime.

Using the reference, you can, however, access methods whose original definition is contained in the class. This is the case with the get_attributes method in the example in the figure. The question here is which implementation of the method will be called. In this case, the system looks at runtime to see what type of object the reference variable is pointing to, and calls the implementation from the corresponding class. In other words, although we are using a plane reference to manage an instance of the passenger plane class, it is still the method implementation from the passenger plane class that is called.

Assigning a Generic Reference to a Specific Type

You can always assign a reference variable with the type of a subclass to a reference variable with the type of a superclass. For example, you can always assign a passenger plane reference to a plane reference. As we have seen, this is because a passenger plane is a plane. Assigning reference variables in the opposite direction, however, is more tricky. This is because a plane reference can contain references to other classes than the passenger plane class. In other words, where every passenger plane is a plane, not every plane is a passenger plane.

Given an object references plane with type ref to lcl_plane and passenger_plane with type ref to lcl_passenger_plane, the system will always allow you to write plane = passenger_plane. However, the assignment passenger_plane = plane leads to a syntax error because the syntax check cannot be sufficiently sure that the plane reference will actually hold a reference to a passenger plane object at that moment.

The CAST Operator

The syntax check does not let you assign a superclass reference directly to a subclass reference. However, you can still do it using the CAST operator. Casting means looking at an object as though it has a different type. In the example, we tell the system to treat "plane" as though it were an instance of the passenger plane class. This is syntactically correct, as we are now pretending that "vehicle" on the right-hand side of the expression has the same type as "passenger" on the left-hand side. However, there is still no guarantee that plane actually contains a passenger plane reference, and if it turns out not to contain one at runtime, the assignment cannot be made. Left unprotected, this assignment could cause a runtime error.

Securing a Down-Cast

If you are not certain that the object to which a reference variable is pointing is actually an instance of the correct subclass, you can check it using the logical expression IS INSTANCE OF. In this example, the assignment to the passenger plane reference is only processed if plane actually points to an instance of the class lcl_passenger_plane.

Try It Out: Subclass Instantiation

  1. Create a new class that implements the interface IF_OO_ADT_CLASSRUN.
  2. Switch to the Local Types tab and copy the following code snippet into the editor:
    Code snippet
    
    CLASS lcl_plane DEFINITION.
    PUBLIC SECTION.
    TYPES: BEGIN OF ts_attributes,
    name TYPE string,
    value TYPE string,
    END OF ts_attributes,
    * declare table - do not allow the same attribute to be used more than once
    tt_attributes TYPE SORTED TABLE OF ts_attributes WITH UNIQUE KEY name.
    
    
    METHODS constructor IMPORTING iv_manufacturer TYPE string
    iv_type TYPE string.
    METHODS: get_Attributes RETURNING VALUE(rt_Attributes) TYPE tt_attributes.
    
    
    PROTECTED SECTION.
    DATA manufacturer TYPE string.
    DATA type TYPE string.
    
    PRIVATE SECTION.
    
    ENDCLASS.
    
    
    CLASS lcl_plane IMPLEMENTATION.
    METHOD constructor.
    manufacturer = iv_manufacturer.
    type = iv_type.
    ENDMETHOD.
    
    
    METHOD get_attributes.
    rt_attributes = VALUE #( ( name = 'MANUFACTURER' value = manufacturer )
    ( name = 'TYPE' value = type ) ) .
    ENDMETHOD.
    
    
    ENDCLASS.
    
    
    CLASS lcl_cargo_plane DEFINITION INHERITING FROM lcl_plane.
    PUBLIC SECTION.
    METHODS constructor IMPORTING iv_manufacturer TYPE string
    iv_type TYPE string
    iv_cargo TYPE i.
    METHODS get_attributes REDEFINITION.
    private section.
    data cargo type i.
    ENDCLASS.
    
    
    CLASS lcl_cargo_plane IMPLEMENTATION.
    METHOD constructor.
    
    
    super->constructor( iv_manufacturer = iv_manufacturer iv_type = iv_type ).
    cargo = iv_cargo.
    
    
    ENDMETHOD.
    
    
    METHOD get_attributes.
    
    
    * method uses protected attributes of superclass
    
    
    rt_attributes = value #( ( name = 'MANUFACTURER' value = manufacturer )
    ( name = 'TYPE' value = type )
    ( name ='CARGO' value = cargo ) ).
    
    
    ENDMETHOD.
    
    
    ENDCLASS.
    
    
    CLASS lcl_passenger_plane DEFINITION INHERITING FROM lcl_Plane.
    PUBLIC SECTION.
    METHODS constructor IMPORTING iv_manufacturer TYPE string
    iv_type TYPE string
    iv_seats TYPE i.
    METHODS get_Attributes REDEFINITION.
    private section.
    data seats type i.
    ENDCLASS.
    
    
    CLASS lcl_passenger_plane IMPLEMENTATION.
    
    
    METHOD constructor.
    
    
    super->constructor( iv_manufacturer = iv_manufacturer iv_type = iv_type ).
    
    
    ENDMETHOD.
    
    
    METHOD get_attributes.
    
    
    * Redefinition uses call of superclass implementation
    
    rt_attributes = super->get_attributes( ).
    rt_Attributes = value #( base rt_attributes ( name = 'SEATS' value = seats ) ).
    
    ENDMETHOD.
    
    ENDCLASS.
    Expand
  3. Switch to the Global Class tab and paste the following code snippet into the implementation of method if_oo_adt_classrun~main( ):
    Code snippet
    
    DATA passenger TYPE REF TO lcl_passenger_Plane.
    DATA cargo TYPE REF TO lcl_cargo_plane.
    DATA plane TYPE REF TO lcl_Plane.
    
    
    
    
    
    
    passenger = NEW #( iv_manufacturer = 'BOEING' iv_type = '737-800' iv_seats = 130 ) .
    cargo = NEW #( iv_manufacturer = 'AIRBUS' iv_type = 'A340' iv_cargo = 60000 ).
    
    
    out->write( 'Output using passenger plane object reference' ).
    out->write( passenger->Get_attributes( ) ).
    
    
    plane = passenger.
    
    
    out->write( 'Output using superclass object reference' ).
    out->write( plane->get_attributes( ) ).
    
    
    * Can't use the superclass reference to get the number of seats of the
    * passenger plane, because the relevent method isn't declared in the superclass.
    
    
    * plane->get_seats( ).
    
    
    * Can't assign the plane directly to a passenger plane reference variable, because
    * not every plane is a passenger plane.
    
    
    *passenger = plane.
    
    
    * Make sure the plane is actually a passenger plane, then force the cast.
    IF plane IS INSTANCE OF lcl_passenger_plane.
    passenger = CAST #( plane ).
    ENDIF.
    
    
    ENDMETHOD.
    Expand
  4. Select CTRL + F3 to activate the class and F9 to execute it as a console app.
  5. Play around with the source code to get familiar with the concepts.

Log in to track your progress & complete quizzes