鳥の巣箱

ネトゲしたり、機械いじったり、ソフト書いたり、山篭ったり、ギャンブルしたりする人

自作クラス作成Tips ー 自作クラスにレコード型のプロパティを持たせる時の注意

自作クラスにレコードプロパティを実装したいという場面は結構あるはずです。
ただ、実装時にはいくつか注意しなければならないことがあります。

レコードプロパティのメンバに代入するときの問題

例えば次のような実装の時

  TTsrRec = record
    Name  : string;
    No    : Integer;
  end;

  TTscData = class(TObject)
    private
      FRec  : TTsrRec;
    published
      property Rec  : TTsrRec read FRec write FRec;
  end;

TTscDataクラスのRecプロパティに値を書き込みたい場合、どうなるでしょうか。

procedure TForm3.FormCreate(Sender: TObject);
var
  data  : TTscData;
begin
  data  := TTscData.Create;
  data.Rec.Name := 'Test';
  data.Rec.No   := 1;
end;

実はこれ、コンパイルできません。
E2064エラーがでます。代入できないんですね。
上のような実装をした場合、これに値を書き込みたい場合はこうなります。

procedure TForm3.FormCreate(Sender: TObject);
var
  data  : TTscData;
  rec   : TTsrRec;
begin
  rec.Name  := 'Test';
  rec.No    := 1;
  data  := TTscData.Create;
  data.Rec  := rec;
end;

実装内容や仕様によっては、この使い方でも問題ないでしょうが
できればレコードのメンバに直接書き込みたいなと思うことも多いでしょう。
ではどうすればいいのか。

レコードを拡張すればいいんです。
Delphiのレコード型はクラス方のような実装ができます。


レコードにプロパティを用意する

レコードの実装を少々変更しました。

type
  TTsrRec = record
    private
      FName : string;
      FNo   : Integer;
      procedure SetName(name:string);
      procedure SetNo(no:integer);
    public
      property Name : string read FName write SetName;
      property No   : Integer read FNo write SetNo;
  end;
implementation

procedure TTsrRec.SetName(name:string);
begin
  FName := name;
end;

procedure TTsrRec.SetNo(no:Integer);
begin
  FNo := no;
end;

プロパティメソッドを実装し、レコードのメンバに書き込みをする場合はそれぞれSetName、SetNoプロシージャが呼び出されます。
このような実装をすると、レコードのメンバに直接値を書き込めるようになります。

見てのとおり、レコード型はクラスのような実装ができ、なんならイベントの実装とかも普通にできます。じゃぁ、クラスと何が違うんやというと。

  • レコードからの継承はできない
  • レコードは可変部分を持てる
  • レコードは値型、クラスは参照型
  • レコードはコンストラクタを使って自動生成されるが、クラスは明示的に生成する
  • レコードのコンストラクタはデフォルトの引数なしがあるため、ユーザー定義のコンストラクタには引数が1つ以上必要
  • レコードはデストラクタを持てない
  • 継承に対応しないので、当然virtualやdynamicなんかもサポートしない。
  • レコードはWin32プラットフォームでインターフェースを実装できない

と、こんなところです。
特に継承できるのか否かは大きいと思います。
なので、どちらで実装するかはケースバイケースでって感じで。