본문 바로가기

ABAP 프로그래밍 개념/Object-Oriented ABAP

ABAP OOP : Polymorphism(다형성) PART3 : Casting

서로 다른 유형의 데이터 객체가 서로 할당될 때 적용되는 변환 규칙과 유사하게(Numc와 Intiger와 같은 데이터 형식의 할당과 유사하게), 다른 static type의 객체(type ref to로 각자 선언된 객체들)들의 할당도 특정 룰에 따릅니다. 원천 참조 객체(source reference object)의 static type이 타겟 참조 객체(target reference object)과 같지 않다면, cast라는 특수한 방법(opertaion)이 일어나야 합니다. 보통 이러한 프로세스를 우리는 casting이라고 부릅니다. 개발에서 cast operation을 사용하기 위해서는, target reference object의 static type이 source reference object의 dynamic type과 같거나 더 포괄적이어야 합니다(일반적이라는 뜻은 보통 같은 hierachy에서 superclass 쪽으로 올라갈수록 더 일반적입니다).

2023.01.15 - [ABAP 프로그래밍 개념/Object-Oriented ABAP] - ABAP OOP : Polymorphism(다형성) PART2 : Static and Dynamic Types

 

ABAP OOP : Polymorphism(다형성) PART2 : Static and Dynamic Types

객체(reference variable)의 Static Type은 reference variable을 정의하는데 사용되는 class 유형입니다. 예를 들어 아래 예시에서볼 수 있듯이 oref 참조는 cl_class라는 클래스를 참조하면서 정의됩니다. 이러한

abapta0903.tistory.com

위 글에서 두 번째 코드 예시를 보면, cl_parent가 cl_child보다 더 일반적입니다.(상위 클래스는 subclass와 비교하면 늘 같거나 더 일반적입니다). 다른말로하면, parent class는 two methods로 실행되는 반면, subclass는 parent class에선 이용할 수 없는 자신만의 세 번째 메소드를 추가하여 구체화할 수 있습니다. 그러므로 parent class는 더 포괄적입니다. 이렇기 때문에, child 객체를 parent 객체로 assign 할 수 있는 것입니다.

ABAP에는 두가지 CAST Operation이 가능한데, 각각 narrowing cast(upcast) 와 widening cast(down cast)입니다. 이것에 대해 더 구체적으로 설명해보도록 하겠습니다. 


Narrowing Cast ( Down Cast )


Narrowing Cast는 타겟 참조 객체(target reference object)의 static type이 source reference object의 static type보다 더 포괄적일 때 사용합니다. 이전 예시에서 봤던 parent, child의 예시는 Narrow Cast인데, parent 클래스가 더 포괄적이기 때문입니다. 이 예시에서 casting(parent = child)된 이후에, parent class는 parent class의 static type에서 정의된 child class의 구성요소에만 오직 접근할 수 있으므로, 효과적으로 접근될 수 있는 구성요소의 스코프(scope)를 줄여줍니다.

예를 들어, parent class는 meth1과 meth2라는 두 개의 메소드를 가지고 있고, child class는 parent class에서 정의되지 않은 meth3라는 부가적인 method를 가지고 있습니다. casting operation 이후에는, 오직 parent에서는 parent 객체 참조를 이용하여 child class의 meth1과 meth2만 오직 접근할 수 있습니다. 만약 meth3에 접근하려고 하면,  아래 예시처럼 syntax error가 발생할 것입니다. 그러나, child 객체 참조를 이용해서는 meth3를 사용할 수 있습니다.

CLASS cl_parent DEFINITION.
 PUBLIC SECTION.
  METHODS meth1.
  METHODS meth2.
ENDCLASS.

CLASS cl_parent IMPLEMENTATION.
 METHOD meth1.
  WRITE 'In method1 of parent'.
 ENDMETHOD.

 METHOD meth2.
  WRITE 'In method2 of parent'.
 ENDMETHOD.
 
ENDCLASS.

CLASS cl_child DEFINITION INHERITING FROM cl_parent.
 PUBLIC SECTION.
  METHODS meth2 REDEFINITION.
  METHODS meth3.
ENDCLASS.

CLASS cl_child IMPLEMENTATION.
 METHOD meth2.
  WRITE 'In method2 of child'.
 ENDMETHOD.

 METHOD meth3.
  WRITE 'In method3 of child'.
 ENDMETHOD.

ENDCLASS.

DATA parent TYPE REF TO cl_parent.
DATA child TYPE REF TO cl_child.

START-OF-SELECTION.
 CREATE OBJECT parent.
 CREATE OBJECT child.
 
Parent->meth2( ).
parent = child.
parent->meth2( ).

Parent = child. "Assigns child reference to parent.
Parent->meth1( )."Calls the method meth1 in child if redefined.
Parent->meth2( )."Calls the method meth2 in child if redefined.
Parent->meth3( )."Results in syntax error.
Child->meth3( )."Works as expected.

Narrow cast는 위처럼 각 객체를 선언해서 Assign 하는 것 뿐만 아니라, CREATE OBJECT 구문에 TYPE를 추가하여 인스턴스화 할 수 있습니다.

DATA parent TYPE REF TO cl_parent.
CREATE OBJECT parent TYPE cl_child.

Widening Cast


Widening Cast는 target reference object의 static type이 source reference object보다 더 구체적일 때 사용합니다. 왜냐하면 이것은 casting를 위한 target object는 항상 source object보다 더 일반적이여야 한다는 규칙을 위배하기 때문에, syntax checker는 = operator나 MOVE 구문을 써서 할당하려고 할 때  source object가 target object로 할당하는 것에 에러를 제시할 것입니다. 이러한 제한을 통과하고 하고자하는 것을 Compiler에게 전달하기 위해서는, Widening cast를 위해선 ?= operator을 사용해야합니다.

Child ?= parent.

?= 구문을 사용하면 컴파일 시간 중에만 정적으로 Syntax Check를 통과하고, 런타임까지 Syntax Check를 연기할 수 있습니다. 즉, 프로그램의 Active 까지는 Syntax Check를 통과시키고, 프로그램의 실행하여 런타임중에 해당 구문의 유효성을 판단한다고 생각하면 됩니다. 그렇기 때문에, target object가 source object보다 일반적(포괄적)이지 않다면 런타임 에러가 발생할 것입니다. 예를 들어, 아래 예시 코드는 Syntax Check는 일어나지 않지만, 실행시에는 런타임 에러가 발생할것인데 그 이유는 Child object(target object)가 parent object(source object)보다 일반적(포괄적)이지 않고 더 구체적이기 때문입니다.

CLASS cl_parent DEFINITION.

 PUBLIC SECTION.
  METHODS meth1.
  METHODS meth2.
  
ENDCLASS.

CLASS cl_parent IMPLEMENTATION.

 METHOD meth1.
  WRITE 'In method1 of parent'.
 ENDMETHOD.

 METHOD meth2.
  WRITE 'In method2 of parent'.
 ENDMETHOD.
 
ENDCLASS.

CLASS cl_child DEFINITION INHERITING FROM cl_parent.

 PUBLIC SECTION.
  METHODS meth2 REDEFINITION.
  METHODS meth3.
  
ENDCLASS.

CLASS cl_child IMPLEMENTATION.

 METHOD meth2.
  WRITE 'In method2 of child'.
 ENDMETHOD.

 METHOD meth3.
  WRITE 'In method3 of child'.
  
 ENDMETHOD.

ENDCLASS.

DATA parent TYPE REF TO cl_parent.
DATA child TYPE REF TO cl_child.

START-OF-SELECTION.

CREATE OBJECT parent.
CREATE OBJECT child.
Child ?= parent. "Results in runtime error

Widening cast는 target object의 dynamic type이 source object보다 더 포괄적(일반적)일 때 사용되어야 합니다. 이는 아래 보여지는 것과 같이, 이는 효과적으로 Widening Cast 이전에 Narrowing Cast는 수행해야됨을 의미합니다. Widening Cast는 어렵고 위험하기 때문에 주의를 가지고 사용해야 합니다.

CLASS cl_parent DEFINITION.
 PUBLIC SECTION.
  METHODS meth1.
  METHODS meth2.
ENDCLASS.

CLASS cl_parent IMPLEMENTATION.
 METHOD meth1.
  WRITE 'In method1 of parent'.
 ENDMETHOD.

 METHOD meth2.
  WRITE 'In method2 of parent'.
 ENDMETHOD.
ENDCLASS.

CLASS cl_child1 DEFINITION INHERITING FROM cl_parent.
 PUBLIC SECTION.
  METHODS meth2 REDEFINITION.
  METHODS meth3.
ENDCLASS.

CLASS cl_child1 IMPLEMENTATION.
 METHOD meth2.
  WRITE 'In method2 of child1'.
 ENDMETHOD.
 
 METHOD meth3.
  WRITE 'In method3 of child1'.
 ENDMETHOD.
ENDCLASS.

CLASS cl_child2 DEFINITION INHERITING FROM cl_child1.
 PUBLIC SECTION.
  METHODS meth2 REDEFINITION.
  METHODS meth3 REDEFINITION.
  METHODS meth4.
ENDCLASS.

CLASS cl_child2 IMPLEMENTATION.
 METHOD meth2.
  WRITE 'In method2 of child2'.
 ENDMETHOD.

 METHOD meth3.
  WRITE 'In method3 of child2'.
 ENDMETHOD.

 METHOD meth4.
  WRITE 'In method4 of child2'.
 ENDMETHOD.
ENDCLASS.

DATA parent TYPE REF TO cl_parent.
DATA child1 TYPE REF TO cl_child1.
DATA child2 TYPE REF TO cl_child2.

START-OF-SELECTION.

CREATE OBJECT parent.
CREATE OBJECT child1.
CREATE OBJECT child2.

parent = child2.

child1 ?= parent.
child1->meth2( ).

cl_parent, cl_child1, child2라는 세 개의 클래스가 정의되있습니다. cl_child1은 cl_parent로부터 상속받고 있고, cl_child2는 child1을 상속받고 있습니다.

child2(source object)라는 객체는 parent(target object)로 먼저 Assigning(할당)함으로서 Narrow cast가 일어나고, 그후에 parent를 child1으로 Assigning(할당)함으로서 Widening Cast가 일어았습니다. Widening Cast 이후에 child1에서 meth2라는 메소드를 호출하였을 때, cl_child2 클래스의 meth2 메소드가 실행 될 것입니다.

즉, 이번 파트에서 이해해야하는 부분은 Source Object가 무엇인지 Target Object가 무엇인지를 알아야 됩니다. 보통 선언을 할 때 Narrow Cast를 예를 들어서 parent = child라고 한다면, parent가 Target, child가 Source가 될 것입니다. 또한, 이 각각의 Object들의 Static Type과 Dynamic Type이 무엇인지 알아야합니다. Static은 어떤 형식으로 선언되었는지를 나타내는 것(Type Ref to로 어떤 형태로 선언 되었는지), Dynamic Type은 시스템의 해당 객체의 인스턴스가 Pointer가 무엇을 바라보고 있는지(Cast, Create Object를 통해 실제 메모리가 어떤 형태를 바라보고 있는지)입니다. 또한 Narrow Cast는 Target의 Static Type가 Source보다 더 Generic해야된다, Widening Cast는 Target Object의 Static Type이 Souce보다 더 Specific(구체적)이어야 합니다.

반응형