Você está na página 1de 16

NARROW CASTING Important principal of the Inheritence is that an instance of the Subclass can be used in all the contexts

where the Superclass can be used. This is possible because the Subclass contains all the attributes of the Superclass, because Subclass has been inhertied from the Super.

When we assign the instance of the Subclass back to the instance of the Superclass, than it is called the Narrow Casting, because we are switching from a More Specific view of an object to less specific view.

For example: we have a class a global class for ANIMAL. Now, we have inherited more specific class as LION from the ANIMAL. Since LION will have all the attributes from the ANIMAL, we can always refer back to ANIMAL with the reference of the LION.

When this Narrow casting is used? An application which is interested in the details of the LION, but dont want to know about them. An application only needs to work with the ANIMAL class. In order to allow the application to access the attributes of the LION we have to do a narrow cast and assign it back to the ANIMAL, which is visible from an application.

UML diagram for the example

Lets check out the UML of the Demo.

In words: LCL_ANIMAL class has a method HUNGRY( ). LCL_LION is inherited from the LCL_ANIMAL. Program is using the LCL_LION to access the instance.

Code Lines

Lets checkout the code lines. [Select all]

*&---------------------------------------------------------------------* *& This code snippet implements the local calss ANIMAL and LION *&---------------------------------------------------------------------* REPORT ztest_narrow_casting. * *----------------------------------------------------------------------* * Animal Super Class defintion *----------------------------------------------------------------------* CLASS lcl_animal DEFINITION. PUBLIC SECTION. METHODS: hungry. ENDCLASS. * "lcl_animal DEFINITION

*----------------------------------------------------------------------* * Lion subclass defintion *----------------------------------------------------------------------* CLASS lcl_lion DEFINITION INHERITING FROM lcl_animal. PUBLIC SECTION. METHODS: hungry REDEFINITION, fasting. ENDCLASS. * * *----------------------------------------------------------------------* * Animal Implementation *----------------------------------------------------------------------* CLASS lcl_animal IMPLEMENTATION. METHOD hungry. WRITE: / 'An animal is hungry'. ENDMETHOD. ENDCLASS. * *----------------------------------------------------------------------* * Lion subclass implementation *----------------------------------------------------------------------* CLASS lcl_lion IMPLEMENTATION. METHOD hungry. WRITE: / 'A Lion (King of Jungle) is hungry.', 'Run as fast as you can..!'. "hungry "lcl_animal IMPLEMENTATION "lcl_lion DEFINITION

ENDMETHOD. METHOD fasting.

"hungry

WRITE: / 'Stop running. Lion is on Fasting today.'. ENDMETHOD. ENDCLASS. "lcl_lion IMPLEMENTATION

*----------------------------------------------------------------------* * This code shows how to use the Narrow casting *----------------------------------------------------------------------* START-OF-SELECTION. DATA: lo_animal TYPE REF TO lcl_animal, lo_lion TYPE REF TO lcl_lion. * * ANIMAL object without NARROW casting WRITE: / 'Animal - without NARROW casting'. CREATE OBJECT lo_animal. CALL METHOD lo_animal->hungry( ). CLEAR lo_animal. * * ANIMAL object with NARROW CASTING SKIP 2. WRITE: / 'Animal - NARROW casting from LION'. CREATE OBJECT lo_lion. lo_animal = lo_lion. CALL METHOD lo_animal->hungry( ). *

* call the method FASTING must be a dynamic because FASTING is not * in the Animal CALL METHOD lo_animal->('FASTING').

Output from this code snippet: Advertisement

WIDENING CASTING When we assign the instance of the Superclass to the Subclass, than it is called the Widening Cast, because we are moving to the More Specific View from the Less specific view.

Everytime it is not possible to move the Superclass reference to the Subclass, because subclass will(or might) have always more functionality compare to the Superclass. So, we need to be more careful when we use the down casting. We will use the same ANIMAL Superclass and LION subclass as per the blog post ABAP Objects: Narrowing Cast When this Widening Cast is used?

Widening cast can be used when we need to access the Specific functionality of the subclass from the Superclass. In ABAP, it is necessary to catch the

exception CX_SY_MOVE_CAST_ERROR while doing the widening cast to avoid the short-dump. Code Lines

Check out the code lines for Widening Cast: [Select all]

*----------------------------------------------------------------------* * This code shows how to use the Widening cast (downcasting) *----------------------------------------------------------------------* START-OF-SELECTION. DATA: lo_animal TYPE REF TO lcl_animal, lo_lion TYPE REF TO lcl_lion, lo_cast_error TYPE REF TO cx_sy_move_cast_error. * * First We have to do Narrow casting in order to set the * Animal reference to LION reference. DATA: lo_tmp_lion TYPE REF TO lcl_lion. CREATE OBJECT lo_tmp_lion. lo_animal = lo_tmp_lion. * * Now, we will do the Widening cast to move the reference from the * Animal to LION (more specific class). TRY. lo_lion ?= lo_animal. CATCH cx_sy_move_cast_error INTO lo_cast_error. WRITE: / 'Widening cast failed 1'. ENDTRY. IF lo_lion IS NOT INITIAL.

CALL METHOD lo_lion->hungry( ). CALL METHOD lo_lion->fasting( ). ENDIF. * * Now, we will try to do the widening cast without setting up * the proper object reference in the Super reference. CLEAR: lo_animal, lo_lion, lo_cast_error. CREATE OBJECT lo_animal. TRY. lo_lion ?= lo_animal. CATCH cx_sy_move_cast_error INTO lo_cast_error. WRITE: / 'Widening cast failed 2'. ENDTRY. IF lo_lion IS NOT INITIAL. CALL METHOD lo_lion->hungry( ). CALL METHOD lo_lion->fasting( ). ENDIF.

Output

Output of this code snippet is:

More on ABAP Objects instanceOf commands Holger Janz

E-Mail Print A AA AAA LinkedIninShare Facebook Twitter Share This Reprints

One year ago a user posted the question: Is there an equivalent to Java's instanceOf-operator in ABAP? The answer in the tip ABAP Objects instanceOf command was quite interesting. The example has one problem. It deals with class names! In ABAP it is possible to have global and local classes and it is possible that a global class has the same name as a local class. The scope of the use of the class name decides what class to use. So this example will not work correctly in some cases.

Actually ABAP has the functionality of an instanceOf-operator. The difference is that it is not an operator but a method of the RTTI. Please see the code example below. You can ask an instance of the RTTI directly whether a given instance belongs to the type described by the RTTI instance or not. This method is quite fast and if you use it in a loop you have to take into account that the RTTI instance has only to be derived once. It does not matter how this RTTI instance is derived (e.g. by RTTI methods DESCRIBE_BY_NAME, DESCRIBE_BY_OBJECT_REF or it is a parameter given from some other service). I hope this tip will help to simplify the code. If you have any further

question about the RTTI or reflection in ABAP in general, do not hesitate to write me. Regards, Holger.Janz@sap.com program rtti_instanceof.

class c00 definition. endclass.

data: class_ref type ref to cl_abap_classdescr, any_object type ref to object.

create object any_object type c00.

* This works also for cl_abap_intfdescr. * In this case APPLIES_TO means whether the interface is implemented * by the instance or it is not. class_ref ?= cl_abap_typedescr=>describe_by_name( 'C00' ).

if abap_true = class_ref->applies_to( any_object ). write / 'Object is intance of C00.'. else. write / 'Object is not intance of C00.'. endif.

ABAP Objects : Interfaces ABAP Objects is essentially employing the concepts of Object Oriented programming in ABAP viz. Encapsulation, Inheritance and Polymorphism.

ABAP has gone through radical changes since its inception in late 60s when it was just a Macro based reporting tool. Somewhere around 80's, it received major facelift and was transformed into 4GL. Hence the name ABAP/4. At the turn of the century, some powerful constructs were added so as to enable ABAP to demonstrate its OO capabilities.

Polymorphism concept is implemented in ABAP Objects using Interfaces. Simply put, polymorphism would mean the same operator would behave in different manner depending on operand objects. E.g. Operator '+'. When the operands are numbers, it would add them up as usual but if they are literals, it would concatenate. This is called Operator Overloading.

Interfaces are virtual entities that just store the definition of Methods and Attributes. The implementation of these methods is left to the class that would implement it.

Using casting techniques, same Interface Reference can point to two objects having different classes which have implemented this Interface.

Just to demonstrate this concept, I've jotted down the following code snippet.

*&---------------------------------------------------------------------* *& Report ZPK_DEMO02 *& *&---------------------------------------------------------------------* *& *& *&---------------------------------------------------------------------*

REPORT zpk_demo02.

*---------------------------------------------------------------------* * CLASS trig_obj DEFINITION

*---------------------------------------------------------------------* * *---------------------------------------------------------------------* CLASS trig_obj DEFINITION. PUBLIC SECTION. METHODS : constructor. CLASS-METHODS : display_count.

PRIVATE SECTION. CLASS-DATA : no_of_obj TYPE i. ENDCLASS. "trig_obj DEFINITION

*---------------------------------------------------------------------* * CLASS trig_obj IMPLEMENTATION

*---------------------------------------------------------------------* * *---------------------------------------------------------------------* CLASS trig_obj IMPLEMENTATION. METHOD constructor. ADD 1 TO no_of_obj. ENDMETHOD. METHOD display_count. MESSAGE i000(38) WITH 'No. of trig. objects created ' no_of_obj. ENDMETHOD. "display_count "constructor

ENDCLASS.

"trig_obj IMPLEMENTATION

*---------------------------------------------------------------------* * INTERFACE trig_functions IMPLEMENTATION

*---------------------------------------------------------------------* * *---------------------------------------------------------------------* INTERFACE trig_functions. METHODS : calculate_perimeter, calculate_area, display_perimeter, display_area. DATA : perimeter TYPE i, area(4) TYPE p DECIMALS 2. ENDINTERFACE. "trig_functions IMPLEMENTATION

*---------------------------------------------------------------------* * CLASS triangle DEFINITION

*---------------------------------------------------------------------* * *---------------------------------------------------------------------* CLASS triangle DEFINITION INHERITING FROM trig_obj.

PUBLIC SECTION. METHODS constructor IMPORTING f_side1 TYPE i f_side2 TYPE i f_side3 TYPE i.

INTERFACES trig_functions. PRIVATE SECTION. DATA : side_a TYPE i, side_b TYPE i, side_c TYPE i. ENDCLASS. "triangle DEFINITION

*---------------------------------------------------------------------* * CLASS triangle IMPLEMENTATION

*---------------------------------------------------------------------* * *---------------------------------------------------------------------* CLASS triangle IMPLEMENTATION. METHOD constructor. CALL METHOD super->constructor. side_a = f_side1. side_b = f_side2. side_c = f_side3. ENDMETHOD. "constructor

METHOD trig_functions~calculate_area. trig_functions~area = ( side_a * side_c ) / 2. ENDMETHOD. "trig_functions~calculate_area

METHOD trig_functions~calculate_perimeter. trig_functions~perimeter = side_a + side_b + side_c. ENDMETHOD. "trig_functions~calculate_perimeter

METHOD trig_functions~display_area. MESSAGE i000(38) WITH 'The area of this object is ' trig_functions~area. ENDMETHOD. "trig_functions~display_area

METHOD trig_functions~display_perimeter. MESSAGE i000(38) WITH 'The perimeter of this object is ' trig_functions~perimeter. ENDMETHOD. ENDCLASS. "trig_functions~display_perimeter "triangle IMPLEMENTATION

*---------------------------------------------------------------------* * CLASS circle DEFINITION

*---------------------------------------------------------------------* * *---------------------------------------------------------------------* CLASS circle DEFINITION INHERITING FROM trig_obj. PUBLIC SECTION. METHODS constructor IMPORTING f_radius TYPE i. INTERFACES trig_functions. PRIVATE SECTION. DATA : radius TYPE i. ENDCLASS. "circle DEFINITION

*---------------------------------------------------------------------* * CLASS circle IMPLEMENTATION

*---------------------------------------------------------------------* * *---------------------------------------------------------------------* CLASS circle IMPLEMENTATION.

METHOD constructor. CALL METHOD super->constructor. radius = f_radius. ENDMETHOD. "constructor

METHOD trig_functions~calculate_area. trig_functions~area = ( radius * radius ) * 22 / 7. ENDMETHOD. "trig_functions~calculate_area

METHOD trig_functions~calculate_perimeter. trig_functions~perimeter = 44 * radius / 7. ENDMETHOD. "trig_functions~calculate_perimeter

METHOD trig_functions~display_area. MESSAGE i000(38) WITH 'The area of this object is ' trig_functions~area. ENDMETHOD. "trig_functions~display_area

METHOD trig_functions~display_perimeter. MESSAGE i000(38) WITH 'The perimeter of this object is ' trig_functions~perimeter. ENDMETHOD. ENDCLASS. "trig_functions~display_perimeter "circle IMPLEMENTATION

PARAMETERS : p_objtyp TYPE c.

START-OF-SELECTION. DATA : wref_functions TYPE REF TO trig_functions,

wref_circle TYPE REF TO circle, wref_triangle TYPE REF TO triangle.

IF p_objtyp = 'C'. CREATE OBJECT wref_circle EXPORTING f_radius = 7. wref_functions = wref_circle. ELSEIF p_objtyp = 'T'. CREATE OBJECT wref_triangle EXPORTING f_side1 = 3 f_side2 = 4 f_side3 = 5. wref_functions = wref_triangle. ENDIF.

IF p_objtyp CA 'CT'. CALL METHOD : wref_functions->calculate_area, wref_functions->display_area, wref_functions->calculate_perimeter, wref_functions->display_perimeter. ELSE. WRITE:/ 'Bad choice!'. ENDIF.

Você também pode gostar