델파이 7 이후 추가된 델파이 언어 기능들

By: Jeehoon Imp Park /Korea

Abstract: 델파이 7 버전 이후에 나온 델파이 언어의 새로운 주요 기능들을 살펴봅시다.

델파이 7 이후 추가된 언어 및 컴파일러 기능들

인라이닝 이제 루틴들을 inline 지시자로 표시할 수 있습니다. 이 지시자는 컴파일러에게 해당 루틴을 실제로 호출하는 대신 호출하는 측에서 해당 루틴을 포함하는 코드를 생성하도록 합니다.
연산자 오버로딩

레코드 선언 내에서 특정 함수나 연산자를 오버로드하는 것을 허용합니다.

TMyClass = class
    class operator Add(a, b: TMyClass): TMyClass; // TMyClass 타입의 두 피연산자를 더함
    class operator Subtract(a, b: TMyClass): TMyclass; // TMyClass 타입의 빼기 연산

    class operator Implicit(a: Integer): TMyClass; // 정수형을 TMyClass 타입으로 암시적으로 변환
    class operator Implicit(a: TMyClass): Integer; // TMyClass 타입을 정수로 암시적으로 변환
    class operator Explicit(a: Double): TMyClass; // Double 타입을 TMyClass 타입으로 명시적으로 변환

end;

// Add 클래스 연산자의 구현 예시
TMyClass.Add(a, b: TMyClass): TMyClass;
begin
  ...
end;

var
x, y: TMyClassbegin
  x := 12; // 정수로부터의 암시적인 변환
  y := x + x; // TMyClass.Add(a, b: TMyClass): TMyClass 호출 

  b := b + 100; // TMyClass.Add(b, TMyClass.Implicit(100)) 호출
end;

클래스 헬퍼

클래스 헬퍼는 다른 클래스와 연관되어 연관된 클래스의 문맥에서 사용될 수 있는 추가 메소드 이름과 프로퍼티를 도입합니다. 클래스 헬퍼는 상속을 이용하지 않고 클래스를 확장할 수 있는 수단입니다. 클래스 헬퍼는 컴파일러가 식별자들을 해석할 때 더 넓은 영역을 도입합니다. 클래스 헬퍼를 선언하려면 헬퍼의 이름과 그 헬퍼로 확장하려는 클래스의 이름을 지정합니다. 확장되는 클래스를 정상적으로 사용할 수 있는 어떤 곳이든 클래스 헬퍼를 사용할 수 있습니다. 컴파일러의 식별 영역(resolution scope)은 원래의 클래스에 클래스 헬퍼를 더한 만큼이 됩니다. 클래스 헬퍼는 클래스를 확장하는 한 방법을 제공하지만, 새로운 코드를 개발할 때 설계 방법으로서 취급되어서는 안됩니다. 클래스 헬퍼는 오직 의도된 목적으로만 사용되어야 하며, 그것은 언어와 플랫폼 RTL의 바인딩을 위한 것입니다.

type
  TMyClass = class

    procedure MyProc;
	function  MyFunc: Integer;
  end;

   ...

   procedure TMyClass.MyProc;
   var

	 X: Integer;
   begin
	  X := MyFunc;
   end;

   function TMyClass.MyFunc: Integer;
   begin
	   ...
   end;

...


type
   TMyClassHelper = class helper for TMyClass
	 procedure HelloWorld;
	 function MyFunc: Integer;
   end;

   ...

   procedure TMyClassHelper.HelloWorld;
   begin

	 WriteLn(Self.ClassName); // 여기서 self는 TMyClassHelper가 아니라 TMyClass 객체입니다.

   end;

   function TMyClassHelper.MyFunc: Integer;
   begin
	 ...
   end;
...


var
  X: TMyClass;
begin
  X := TMyClass.Create;
  X.MyProc;    // TMyClass.MyProc 호출
  X.HelloWorld; // TMyClassHelper.HelloWorld 호출
  X.MyFunc; // TMyClassHelper.MyFunc 호출

end;
strict private private 키워드는 실제로는 동일한 유닛에 포함된 클래스들 사이에서는 "친구 관계"를 허용합니다. strict private 선언은 진정한 private 필드를 만들 수 있게 해주는 것으로, 동일 유닛의 클래스들을 포함해서 다른 클래스에서는 보여지지 않습니다.
strict protected strict private 선언과 비슷한 것으로, strict protected는 진정한 protected 멤버를 만들 수 있게 해주는 것으로, 선언된 클래스와 그 상속 클래스들에서만 보여집니다.
record에서 메소드 포함 가능

record 선언에서 필드 외에도 프로퍼티, 메소드(생성자도 포함됨), 클래스 프로퍼티, 클래스 메소드, 클래스 필드, 네스티드 타입을 가질 수 있게 되었습니다.


type
  TMyRecord = record

    type
      TInnerColorType = Integer;
    var
      Red: Integer;
    class var
      Blue: Integer;
    procedure printRed();
    constructor Create(val: Integer);
    property RedProperty: TInnerColorType read Red write Red;
    class property BlueProp: TInnerColorType read Blue write Blue;
  end;


constructor TMyRecord.Create(val: Integer);
begin
  Red := val;
end;

procedure TMyRecord.printRed;
begin
  writeln('Red: ', Red);

end;
class abstract

메소드 뿐만 아니라 클래스도 abstract로 선언될 수 있습니다.


type
  TAbstractClass = class abstract
    procedure SomeProcedure;
end;
class sealed sealed로 표시된 클래스는 상속이 불가능합니다.

type
  TAbstractClass = class sealed
    procedure SomeProcedure;

end;
class 상수 이제 클래스는 클래스 상수를 가질 수 있습니다. 이것은 클래스의 객체가 아니라 클래스 자체와 연관된 상수입니다.

type
  TClassWithConstant = class
    public 
      const SomeConst = '이것은 클래스 상수입니다.';
  end;
			

procedure TForm1.FormCreate(Sender: TObject);

begin
  ShowMessage(TClassWithConstant.SomeConst);
end;
클래스 타입 이제 클래스는 해당 클래스 내에서만 사용 가능한 타입 선언을 포함할 수 있습니다.

type
  TClassWithClassType = class
  private
	type

	  TRecordWithinAClass = record
	  SomeField: string;
	end;
  public

	    class var

	  RecordWithinAClass: TRecordWithinAClass;
  end;
  ...
procedure TForm1.FormCreate(Sender: TObject);
begin
  TClassWithClassType.RecordWithinAClass.SomeField := '이것은 클래스 타입으로 선언된 필드입니다.';
  ShowMessage(TClassWithClassType.RecordWithinAClass.SomeField);
end;

class var 클래스는 클래스 변수도 가질 수 있는데, 이것은 클래스의 객체가 아닌 클래스 자체에 적용되는 변수입니다. 예제는 위의 "클래스 타입"을 참고하십시오.
클래스 프로퍼티 클래스 프로퍼티는 클래스의 객체가 아닌 클래스 자체에 적용되는 프로퍼티입니다. 아래의 "static class methods" 예제를 참고하십시오.
중첩된 클래스 클래스 선언 내에서 타입 선언이 포함될 수 있습니다. 이 방법으로 개념적으로 관계가 있는 타입들을 같이 둘 수 있으며, 이름 충돌도 피할 수 있습니다.

type
  TOuterClass = class

  strict private
	MyField: Integer;
  public
	type
      TInnerClass = class
	  public

        MyInnerField: Integer;
		procedure InnerProc;
      end;
      procedure OuterProc;
  end;

procedure TOuterClass.TInnerClass.InnerProc;
begin

  ...
end;
파이널 메소드 오버라이드한 버추얼 메소드를 final로 표시하여 상속되는 클래스에서 해당 메소드를 더 이상 오버라이드하지 못하도록 막을 수 있습니다.

TAbstractClass = class abstract
  public
    procedure Bar; virtual;
  end;

  TSealedClass = classsealed(TAbstractClass)
  public
    procedure Bar; override;
  end;

  TFinalMethodClass = class(TAbstractClass)
  public

    procedure Bar; override; final;
  end;
sealed 메소드 sealed로 표시된 클래스는 더 이상 상속이 불가능합니다. '파이널 메소드'의 예제를 참조하십시오.
클래스 스태틱 메소드 클래스에 스태틱 클래스 메소드를 추가할 수 있는데, 이것은 클래스 타입으로부터 호출할 수 있는 메소드입니다. 클래스 스태틱 메소드는 객체에 대한 참조 없이도 사용이 가능합니다. 일반적인 클래스 메소드와는 달리, 클래스 스태틱 메소드는 Self 파라미터를 가지지 않습니다. 또한 객체의 멤버들을 액세스할 수도 없습니다. (클래스 필드, 클래스 프로퍼티, 클래스 메소드는 액세스할 수 있습니다) 또한 클래스 메소드와 달리 클래스 스태틱 메소드는 virtual로 선언될 수 없습니다.

type
  TMyClass = class
    strict private

      class var
        FX: Integer;
    strict protected  

    // 노트: 클래스 프로퍼티를 액세스하려면 클래스 스태틱으로 선언되어야 합니다.

      class function GetX: Integer; static;
	  class procedure SetX(val: Integer); static;
    public

      class property X: Integer read GetX write SetX;
	  class procedure StatProc(s: String); static;
  end;

TMyClass.X := 17;
TMyClass.StatProc('Hello');

for-in 루프 델파이 2007 for Win32에서는 컨테이너에 대해 for-요소-in-컬렉션 스타일의 반복자를 지원합니다. 컴파일러는 다음의 컨테이너 반복 패턴을 인식합니다.

  for Element in ArrayExpr do Stmt;
  for Element in StringExpr do Stmt;
  for Element in SetExpr do Stmt;
  for Element in CollectionExpr do Stmt;

Server Response from: ETNASC02