zoukankan      html  css  js  c++  java
  • 学习 TList 类的实现[8]

    现在准备建立 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;
    
    至此, 我们可以使用 List.Itmes[i] 的方式访问列表中的元素了;

    再进一步, 让它成为默认属性吧; 尽管只能选择一个属性为默认属性, 但哪一个属性能比它更重要的呢?
    //只需把在 public 区声明的:
    property Items[Index: Integer]: Pointer read GetItems write SetItems;
    
    //改为:
    property Items[Index: Integer]: Pointer read GetItems write SetItems; default;
    
    Items 就是默认属性了, 这样再访问一个元素时, 即可以用: List.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.
    
  • 相关阅读:
    P2048 [NOI2010]超级钢琴
    [LOJ#6468.] 魔法
    [牛客小白月赛18] Forsaken的数列
    [JSOI2011]柠檬
    [TJOI2015]组合数学
    【单调队列优化】[CF372C] Watching Fireworks is Fun
    【线段树】[Luogu P4198]楼房修建
    Python资源
    人生的几个阶段
    两种解读,生活的意义和方法
  • 原文地址:https://www.cnblogs.com/del/p/1131210.html
Copyright © 2011-2022 走看看