Delphi 7以降の言語およびコンパイラの新機能

By: Tomohiro Takahashi

Abstract: Delphi 7以降にリリースされたDelphiに搭載された、数多くの新しい言語機能を解説します。

Delphi 7以降の言語およびコンパイラの新機能

インライン化 ルーチンにinline指令を指定できるようになりました。 これは、コンパイラに対して、そのルーチンを実際に呼び出す代わりに、呼び出し側にそのルーチンを含むコードを出力するよう指示します。
演算子のオーバーロード

Delphiでは、いくつかの関数または演算子をレコード宣言内でオーバーロードできます。


TMyClass = record
    class operator Add(a, b: TMyClass): TMyClass; // Addition of two operands of type TMyClass
    class operator Subtract(a, b: TMyClass): TMyclass; // Subtraction of type TMyClass
    class operator Implicit(a: Integer): TMyClass; // Implicit conversion of an Integer to type TMyClass
    class operator Implicit(a: TMyClass): Integer; // Implicit conversion of TMyClass to Integer
    class operator Explicit(a: Double): TMyClass; // Explicit conversion of a Double to TMyClass
end;

// Example implementation of Add class operator 
TMyClass.Add(a, b: TMyClass): TMyClass;
begin
  ...
end;

var
x, y: TMyClass
begin
  x := 12; // Implicit conversion from an Integer 
  y := x + x; // Calls TMyClass.Add(a, b: TMyClass): TMyClass 
  b := b + 100; // Calls TMyClass.Add(b, TMyClass.Implicit(100)) 
end;

クラスヘルパー

クラスヘルパーは、別のクラスに関連付けられて、そのクラス(またはその派生クラス)のコンテキスト下において使用される追加のメソッドおよびプロパティを導入するための型です。クラスヘルパーは、継承を使用することなくクラスを拡張する手法です。クラスヘルパーは単に、コンパイラが識別子を解決する際に使用するスコープを広げます。クラスヘルパーを宣言する場合は、ヘルパー名とヘルパーによって拡張するクラス名を指定します。クラスヘルパーは、拡張クラスを使用できる場所ならどこでも使用できます。コンパイラの解決スコープは,元のクラスとクラスヘルパーを合わせたものになります。クラスヘルパーはクラスを拡張する手法を提供しますが、新規にコードを開発する際に使用する設計手法とは考えないでください。クラスヘルパーは、言語とプラットフォーム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 refers to TMyClass type, not TMyClassHelper
   end;

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

var
  X: TMyClass;
begin
  X := TMyClass.Create;
  X.MyProc;    // Calls TMyClass.MyProc
  X.HelloWorld; // Calls TMyClassHelper.HelloWorld
  X.MyFunc; // Calls TMyClassHelper.MyFunc
end;
strict private privateキーワードは実際には同一ユニット内のクラス間に「フレンド」な関係を作成します。 strict private宣言は、同一ユニット内のクラスはもちろんのこと、他のクラスからは見えない、真にプライベートなフィールドを作成します。
strict protected strict private宣言と同様に、strict protectedは、それを宣言したクラスおよび派生クラスからしか見えない、真にプロテクテッドなメンバーを作成します。
メソッドを持つレコード

レコードは、フィールドに加えて、プロパティ/メソッド(コンストラクタも含む)/クラスプロパティ/クラスメソッド/クラスフィールド/ネストした型を持てるようになりました。

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;
abstractクラス

メソッドだけでなく、クラスもabstractを宣言できるようになりました。

type
  TAbstractClass = class abstract
    procedure SomeProcedure;
end;
sealedクラス sealedが指定されたクラスは継承して拡張するはできません。
type
  TAbstractClass = class sealed
    procedure SomeProcedure;
end;
クラス定数 クラスは、クラス定数を持てるようになりました。これは、クラスのインスタンスごとではなく、クラスそのものに付随する定数です。
type
  TClassWithConstant = class
    public 
      const SomeConst = 'This is a class constant';
  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 := 'This is a field of a class type declaration';
  ShowMessage(TClassWithClassType.RecordWithinAClass.SomeField);
end;
クラスフィールド クラスは、クラスのインスタンスごとではなく、クラス単体で利用可能なクラス変数を持てるようになりました。「クラス型」の例を参照してください。
クラスプロパティ クラスは、クラスのインスタンスに対してではなく、クラスへの参照に対するプロパティであるクラスプロパティを持てるようになりました。  クラスプロパティへのアクセッサは、クラスメソッドかクラス変数でなければなりません。  「静的なクラスメソッド」の例を参照してください。
ネストしたクラス クラス宣言の中で、ネストした型宣言が可能になりました。これは、概念的に関連する型をまとめたり、名前の競合を回避するための手段になります。
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メソッド

オーバーライドしたvirtualメソッドにfinal指令を指定できるようになりました。これにより、派生クラスがそのメソッドをオーバーライドするのを防ぎます。

  TAbstractClass = classabstract
  public
    procedure Bar; virtual;
  end;

  TSealedClass = class sealed(TAbstractClass)
  public
    procedure Bar; override;
  end;

  TFinalMethodClass = class(TAbstractClass)
  public
    procedure Bar; override; final;
  end;
sealedメソッド sealedを指定したクラスは継承による拡張はできません。「finalメソッド」の例を参照してください。
静的なクラスメソッド クラスは静的なクラスメソッドを持てるようになりました。例えば、クラス型を使って呼び出し可能なメソッドです。静的なクラスメソッドは、オブジェクトの参照無しにアクセス可能です。クラスの通常のメソッドとは違い、静的なクラスメソッドはSelfパラメータを有しません。あらゆるインスタンスメンバにアクセスすることもできません(クラスフィールド/クラスプロパティ/クラスメソッドにはアクセス可能です)。クラスのメソッドとは違い、静的なクラスメソッドはvirtual宣言することもできません。
type
  TMyClass = class
    strict private
      class var
        FX: Integer;
    strict protected

      // Note: accessors for class properties must be declared class static.

      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ループ Delphi 2007 for Win32は、コンテナに対する for-element-in-collection 形式の繰り返しをサポートします。次に、コンパイラが認識するコンテナ繰り返しパターンを示します。
  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: ETNASC03