Implementing Inheritance

Objectives

After completing this lesson, you will be able to:

  • Implement a specialized class

Inheritance Implementation

Watch this video to understand the concept of general and more specialized classes.

Inheritance - The "Is A" Relationship

In modeling, we talk about specialization. The implementation of this relationship in a programming language uses the concept of inheritance, in which a new class (the subclass) is derived from an existing one (the superclass). A reliable test to see if there is a genuine inheritance relationship between two classes is to try to say "a subclass is a superclass". If this is clearly true, you have an inheritance relationship. If it is clearly not true, or even sounds a bit strange, you do not have an inheritance relationship and should not implement one as it will likely cause problems further down the line. When testing our model, we can definitely say that "a cargo plane is a plane " and "a passenger plane is a plane".

A class that inherits from a superclass automatically contains all of the components of the superclass. So, for example, the passenger plane class has a manufacturer and a type just as a plane does. This should not be surprising, as a passenger plane is a plane. What may at first appear suprising is that the passenger plane class cannot access its own manufacturer and type. This is because they are private attributes of the superclass and, as such, they are not accessible to the subclass. Later on you will learn a way of allowing a subclass to access components of a superclass without making them fully public.

Defining the Inheritance Relationship

In ABAP, you implement inheritance using the INHERITING FROM addition in the class definition statement. In this example, the passenger plane class is defined as a subclass of the plane class. Note that the subclass knows its superclass, but the airplane class has no idea what subclasses it has (if any).

A subclass may only have one direct superclass.

One Superclass - Any Number of Subclasses

The plane class may have any number of subclasses, but it does not know about any of them.

Each subclass has a single direct superclass. It knows its superclass, but does not know about any sibling classes (other classes that are derived from the same superclass). In our example, the passenger plane class has no knowledge of the cargo plane class.

How to Extend a Subclass

Once you have declared a subclass, you need to add new components to it or change the existing components. This is what turns the mere copy of the plane class into a passenger plane or a cargo plane. Thanks to inheritance, you do not need to implement the class from scratch - you merely extend it by the new components that it needs.

There are three ways to do this:

Declaring New Components

You can extend a subclass by declaring new components. These are visible to the class itself but not to the superclass, and also not to any other classes that inherit from the same superclass. You therefore need to consider whether the new components are only relevant in the current class or if they actually need to be declared in the superclass.

Protected Components

Even though a subclass contains all of the attributes of its superclass, it is not allowed to access the private components directly by itself. Sometimes this is necessary, but there are other times when a superclass needs to let its subclasses access particular attributes or methods without making them fully public. It can do so by declaring them in the protected section. Protected components are visible within the class itself but also to all subclasses.

In the class definition, you introduce the protected section using the statement PROTECTED SECTION. You must always declare the visibility sections in the sequence PUBLIC SECTION - PROTECTED SECTION - PRIVATE SECTION.

You can move an existing component of a class using a quick fix. To do so, place the cursor on the name of the component in ADT and press Ctrl + 1, then choose the quick fix make <element> protected.

Moving a private component to the protected section is a compatible change - you have broadened the visibility of the component. However, making a public component protected is an incompatible change and could cause syntax errors. This is because you have restricted the visibility of the component, which might already have been used outside the inheritance hierarchy.

Redefining Methods

Superclasses often contain methods that you want to use in a subclass, but their implementations are unsuitable as they do not take into account the particular nature of the subclass. For example, the get_attributes method of the plane class cannot return attributes that are defined in the passenger plane class. However, the passenger plane class still needs a method get_attributes.

In ABAP, you can solve this problem by redefining the instance method get_attributes. When you redefine a method, you write a new implementation for it in the subclass that takes into account things that only the subclass can know. However, the definition of the method stays exactly the same. You must follow these rules:

  • The method retains the same name
  • You indicate that you want to redefine the method by declaring it in the subclass with the addition REDEFINITION.
  • The method has the same visibility as in the superclass
  • You must not change the signature of the method

You cannot redefine a static method.

Implementing the Redefinition

When you implement the redefinition of a method, you can call the implementation in the superclass. You do this using the implicit object reference super, which points to the superclass within the current instance. In this way, you can re-use the method implementation from the superclass and then add to it in your own implementation.

You do not need to declare the reference variable super. It is automatically available within the implementation of redefined methods.

Calling the method in the superclass in this way is optional. Sometimes it will be a good idea, sometimes there is nothing to be gained by it.

New Constructor Definition

In a subclass, you may define a new constructor. In contrast to method redefinitions, a constructor may have its own signature. The signature of a constructor will often contain the same parameters as the constructor of the superclass, plus new parameters of its own. This is because the new instance constructor has two tasks - firstly to call the constructor of the superclass, and then to take care of initalizing its own attributes that are specific to the subclass.

As well as defining a new constructor, you can also define a new static constructor in a subclass.

Role of the Constructor

The constructor of a subclass has two functions; it must ensure that the instance of the superclass is properly created, and after that, it can set the initial values of its own attributes.

In our example, since a passenger plane is a plane, there can be no passenger plane instance unless the constructor of the plane class has run successfully to set the manufacturer and type of the new passenger plane. Only after this can the passenger plane class set its own attributes.

The constructor of the subclass must therefore be able to set not only its own attributes, but to pass the required values to the constructor of the superclass. This is why the signature of the constructor in the subclass often contains the entire signature of the constructor that it is required to call.

Sequence of New Constructor Implementation

In the implementation of the new constructor, there is a particular sequence of operations that you must observe. The most important event is the call to the constructor of the superclass. This is obligatory and you call the method using the implicit reference super, just as you can when calling the original implementation of a redefined method. Once again, you do not need to explicitly declare super.

Before you have called the constructor of the superclass, you must not address any instance components of the instance that is under construction. You may address static components of the class and check the correctness of the importing parameters of the constructor. If they are not correct, raise an exception.

Once the constructor of the superclass has run successfully, you may address the instance components of your new instance.

Sequence of Constructor Calls

The figure illustrates the sequence in which static and instance constructors are called. The example assumes that a program wants to instantiate the passenger plane class and that the plane class has not previously been addressed.

When the program tries to create an instance of the passenger plane class, the runtime system automatically calls the static constructors sequentially, starting at the top of the inheritance hierarchy. Once all of the static constructors have run, the runtime system calls the instance constructor of the subclass, which in turn calls the instance constructor of the superclass.

Try It Out: Inheritance Implementation

  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. Activate the class by pressing Ctrl + F3.
  4. Familiarize yourself with the source code by using editor features like F2 documentation and the navigation functions.
    Note
    There is no executable code in this example.

Log in to track your progress & complete quizzes