본문 바로가기
프로그래밍/PC

FPC 오브젝트(object) 형

by 사악신 2014. 4. 17.


최초 객체지향 프로그래밍(OOP)이 소개되었을 때, 터보 파스칼(TP)은 record 를 확장한 object 형을 사용하였습니다. 현재 델파이의 경우 class 를 주로 사용하지만 여전히 object 형을 지원하고 있으며 이는 프리 파스칼(FPC) 도 마찬가지입니다. 다음은 레퍼런스 문서에 있는 내용을 제 개인적 기준으로 요약 정리해 보았습니다.^^ 매뉴얼에서는 멤버 변수를 field 로 지칭하고 있습니다.



1. Declaration


type

  TObj = object

  private

    Caption: ShortString;

  public

    constructor Init;

    destructor done;


    procedure SetCaption(AValue: String);

    function GetCaption: String;

  end;


private 영역의 경우 델파이와 마찬가지로 같은 유닛 내에서는 friendly 관계입니다. 참고로 class 에서는 strict private 와 같은 문법이 보강되었습니다.(MacPas 모드에서 맥의 여타 파스칼과 호환을 위하여 object 키워드가 class 키워드로 대체되었습니다. 즉, MacPas 모드에서는 오브젝트형을 사용할 수 없습니다.)


FPC 에서는 packed record 처럼 packed object 를 사용할 수 있습니다.



2. Fields


레코드와 유사하며 사용법도 비슷합니다.


type

  TAnObject = object

    AField: LongInt;

    procedure AMethod;

  end;


var

  AnObject: TAnObject;


AnObject.AField := 0;


Self : 자신의 인스턴스를 가리킵니다.


procedure TAnObject.AMethod;

begin

  ...

  Self.AField := 0;

  ...

end;


with 문의 경우...


with AnObject do

begin

  AField := 12;

  AMethod;

end;



3. Static fields


{$STATIC ON} 이 선언되면, 오브젝트는 static field 를 가질 수 있습니다. 흔히 알고 있는 클래스의 static field 를 생각하면 됩니다. 물론, 델파이에서는 비교적 후에 추가(class var)되었지만...^^ (이 녀석이 없어서 Singleton 패턴 구현시 전역 변수를 사용하거나 클래스 내에 const 로 선언한 변수의 포인터를 사용하는 등... 편법을 동원하곤 했습죠. 과거의 이야기네요. ㅎ)


{$static on}

type

  TCL = object

    L: LongInt; static;

  end;


var

  CL1, CL2: CL;

begin

  CL1.L := 2;

  WriteLn(CL2.L);

  CL2.L := 3;

  WriteLn(CL1.L);

  WriteLn(TCL.L);

end.


결과는 다음과 같습니다.


2

3

3



4. constructors and destructors


오브젝트가 virtual 메소드를 사용해야한다면 constructor 와 destructor 가 쌍으로 필요합니다. virtual 메소드를 사용하면 몇 가지 내부적으로 정리해야할 부분(VMT의 초기화)이 생기기 때문입니다.


내부적으로는 이렇게 선언됩니다.


constructor init(_vmt : pointer; _self : pointer ...);

destructor done(_vmt : pointer; _self: pointer ...);


확장된 문법으로 New 와 Dispose 함수를 제공하는데 스택이 아닌 힙(동적 메모리)에 인스턴스를 생성하게 됩니다. 이때 생성자(constructor)의 이름도 함께 사용됩니다.


type

  TObj = object;

    constructor Init;

    ...

  end;


  PObj = ^TObj;


var

  PP: PObj;

begin

  PP := New(PObj, Init);


  또는


  New(PP, Init);


  또는


  New(PP);

  PP^.Init;


end;


마지막의 경우 오브젝트의 인스턴스를 사용하여야한다는 경고가 발생할 수 있습니다. 힙에 생성된 오브젝트를 해제하기 위하여 Dispose 함수를 사용하며, 마찬가지로 소멸자(destructor)의 이름이 함께 사용됩니다.



5. methods


뭐... 일반적인 클래스 사용법이랑 동일합니다. Self 도 마찬가지구요.


5.1 declaration


TP 나 델파이의 경우, field 는 메소드의 앞에 선언되어야 합니다. 하지만 FPC 는 상관없습니다. 아래 코드는 컴파일시 TP 와 델파이에서 오류가 발생하지만 FPC 에서는 발생하지 않습니다.


type

  MyObj = object

    procedure DoIt;

    Field: LongInt;

  end;


5.2 method invocation


static methods


abstract 또는 virtual 이 선언되지 않은 메소드입니다.


type

  TParent = object

    ...

    procedure DoIt;

    ...

  end;

  PParent  = ^TParent;


  TChild = object(TParent)

    ...

    procedure DoIt;

    ...

  end;

  PChild = ^TChild;


상기 소스를 다음과 같이 실행해보면...


var

  ParentA, ParentB: PParent;

  Child: PChild;

begin

  ParentA := New(PParent, Init);

  ParentB := New(PChild, Init);

  Child := New(PChild, Init);

  ParentA^.DoIt; // TParent 의 DoIt 이 호출

  ParentB^.DoIt; // TParent 의 DoIt 이 호출

  Child^.DoIt; // TChild 의 DoIt 이 호출


클래스에서 다형성을 말하는 것이구요. 이 경우는 메소드가 컴파일시 결정되기 때문에 override 되지 않는 현상입니다.(다형성 X)


virtual methods


TParent 와 TChild 의 DoIt 메소드에 virtual 을 모두 선언하면,


  procedure DoIt; virtual;


결과가 다음과 같이 바뀝니다.(다형성 O)


  ParentA^.DoIt; // TParent 의 DoIt 이 호출

  ParentB^.DoIt; // TChild 의 DoIt 이 호출

  Child^.DoIt; // TChild 의 DoIt 이 호출


제 개인적으로는 이러한 다형성이 결국 객체지향 프로그램의 핵심이라고 생각합니다. 상속 또한 다형성을 위해 사용된다고 할까요? 초기 OOP 가 등장했을 때는 상속이 최고인줄 알았지만 말입니다. ^^


아, 그리고 클래스에서처럼 inherited 사용이 가능합니다.(예전 TP 에선 이런거 없었는데 말이죠.)


procedure TChild.DoIt;

begin

  inherited DoIt;


  ...

end;


inherited 는 virtual 메소드에서만 사용이 가능합니다. VMT 와 관련하여, FPC 프로그래머 가이드에서 좀 더 자세한 내용을 확인할 수 있습니다.


인스턴스는 이렇게 메모리에 생성되고...

VMT 는 이렇게 생성됩니다.



abstract methods


추상 메소드는 virtual 메소드의 일종입니다. 델파이와 달리 abstract 메소드가 선언된 놈을 인스턴스화하려고하면 컴파일시 에러가 발생합니다. 사실 델파이만 좀 특이한거죠.^^



6. visibility


private, protected, public 은 클래스와 동일합니다.



이상 오브젝트형을 정리해 보았는데요. 과거 터보 파스칼 시절이 새록새록 떠오르네요. Turbo Vision 의 프리파스칼 버전인 Free Vision 의 경우, 이 오브젝트형을 적절히 사용하고 있습니다. 그래서 이 놈을 살펴봤네요. ^^


반응형

댓글