学習TListクラスの実装[8]

5912 ワード

Items配列プロパティを作成する準備ができました.publicセクションに次のコードを入力します.
property Items[Index: Integer]: Pointer;
Shift+Ctrl+Cを実行したコードは次のとおりです.


...



  TMyList = class(TObject)

  private

    ...

    function GetItems(Index: Integer): Pointer;

    procedure SetItems(Index: Integer; const Value: Pointer);

  public

    ...

    property Items[Index: Integer]: Pointer read GetItems write SetItems;

  end;



implementation



{ TMyList }



...



function TMyList.GetItems(Index: Integer): Pointer;

begin



end;



procedure TMyList.SetItems(Index: Integer; const Value: Pointer);

begin



end;



end.


 
   
TListクラスにおいてGetItemsメソッドはGetと命名される.SetItemsメソッドの名前はPut.ここでは名前を変えるつもりはありません.
それぞれ次のように実現されます.


function TMyList.GetItems(Index: Integer): Pointer;

begin

  if (Index < 0) or (Index >= FCount) then

    raise Exception.CreateFmt(' :%d', [Index]);

  Result := FList^[Index];

end;



{ ,   Notify  ,   TMyList  }

procedure TMyList.SetItems(Index: Integer; const Value: Pointer);

begin

  if (Index < 0) or (Index >= FCount) then

    raise Exception.CreateFmt(' :%d', [Index]);



  if Value <> FList^[Index] then

    FList^[Index] := Value;

end;


 
   
これで、リストを使用できます.Itmes[i]方式でリストの要素にアクセスしました.
さらに、デフォルトのプロパティにしましょう.デフォルトのプロパティは1つしか選択できませんが、どのプロパティがより重要ですか?


//  public  :

property Items[Index: Integer]: Pointer read GetItems write SetItems;



// :

property Items[Index: Integer]: Pointer read GetItems write SetItems; default;

Itemsはデフォルト属性である、これにより、もう1つの要素にアクセスする場合、リストを使用することができる.Itmes[i]; 使用することもできる:List[i].デフォルトのプロパティは便利ですね.
TMyListクラスの現在のすべてのコードを見てみましょう.


unit MyList;



interface



uses SysUtils;



const

  MaxListSize = Maxint div 16;



type

  PPointerList = ^TPointerList;

  TPointerList = array[0..MaxListSize - 1] of Pointer;



  TMyList = class(TObject)

  private

    FList: PPointerList;

    FCount: Integer;

    FCapacity: Integer;

    procedure SetCapacity(const Value: Integer);

    procedure SetCount(const Value: Integer);

    function GetItems(Index: Integer): Pointer;

    procedure SetItems(Index: Integer; const Value: Pointer);

  public

    destructor Destroy; override;

    function Add(Item: Pointer): Integer;

    procedure Clear;

    procedure Delete(Index: Integer);

    property Capacity: Integer read FCapacity write SetCapacity;

    property Count: Integer read FCount write SetCount;

    property List: PPointerList read FList;

    property Items[Index: Integer]: Pointer read GetItems write SetItems; default;

  end;



implementation



{ TMyList }



function TMyList.Add(Item: Pointer): Integer;

begin

  if FCount = FCapacity then SetCapacity(FCapacity + 4);

  FList^[FCount] := Item;

  Result := FCount;

  Inc(FCount);

end;



procedure TMyList.Clear;

begin

  SetCount(0);

  SetCapacity(0);

end;



procedure TMyList.Delete(Index: Integer);

begin

  if (Index < 0) or (Index >= FCount) then

    raise Exception.CreateFmt('  Index:%d', [Index]);

  if Index < FCount then

    System.Move(FList^[Index+1], FList^[Index], (FCount-Index)* SizeOf(Pointer));

  Dec(FCount);

end;



destructor TMyList.Destroy;

begin

  Clear;

  inherited;

end;



procedure TMyList.SetCapacity(const Value: Integer);

begin

  if (Value < FCount) or (Value > MaxListSize) then

    raise Exception.CreateFmt(' :%d', [Value]);

  if FCapacity <> Value then

  begin

    ReallocMem(FList, Value * SizeOf(Pointer));

    FCapacity := Value;

  end;

end;



procedure TMyList.SetCount(const Value: Integer);

var

  i: Integer;

begin

  if (Value < 0) or (Value > MaxListSize) then

    raise Exception.CreateFmt(' :%d', [Value]);

  if Value > FCapacity then SetCapacity(Value);

  if Value > FCount then

    FillChar(FList^[FCount], (Value - FCount) * SizeOf(Pointer), 0)

  else

    for i := FCount - 1 downto Value do

      Delete(I);

  FCount := Value;

end;



function TMyList.GetItems(Index: Integer): Pointer;

begin

  if (Index < 0) or (Index >= FCount) then

    raise Exception.CreateFmt(' :%d', [Index]);

  Result := FList^[Index];

end;



procedure TMyList.SetItems(Index: Integer; const Value: Pointer);

begin

  if (Index < 0) or (Index >= FCount) then

    raise Exception.CreateFmt(' :%d', [Index]);



  if Value <> FList^[Index] then

    FList^[Index] := Value;

end;



end.


 
   
要素へのアクセスが便利になり、前のテストをやり直します.


unit Unit1;



interface



uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls;



type

  TForm1 = class(TForm)

    procedure FormCreate(Sender: TObject);

  end;



var

  Form1: TForm1;

implementation



{$R *.dfm}



uses MyList;



type

  TMyRec = record

    name: string[8];

    age : Word;

  end;



procedure TForm1.FormCreate(Sender: TObject);

var

  ListA: TMyList;

  r,r1,r2,r3,r4,r5: TMyRec;

begin

  ListA := TMyList.Create;



  r1.name := ' ';

  r1.age  := 11;

  ListA.Add(@r1);



  r2.name := ' ';

  r2.age  := 22;

  ListA.Add(@r2);



  r3.name := ' ';

  r3.age  := 33;

  ListA.Add(@r3);



  r4.name := ' ';

  r4.age  := 44;

  ListA.Add(@r4);



  r5.name := ' ';

  r5.age  := 55;

  ListA.Add(@r5);





  { }

  //r := TMyRec(ListA.List^[2]^);          { }

  r := TMyRec(ListA[2]^);

  ShowMessageFmt('%s:%d',[r.name, r.age]); { :33}



  { }

  ListA.Delete(2);

  //r := TMyRec(ListA.List^[2]^);          { }

  r := TMyRec(ListA[2]^);

  ShowMessageFmt('%s:%d',[r.name, r.age]); { :44}



  {  Items  ,  ,  }

  ListA[2] := @r1;

  r := TMyRec(ListA[2]^);

  ShowMessageFmt('%s:%d',[r.name, r.age]); { :11}



  ListA.Free;

end;



end.