• 学习 TList 类的实现[4]


    现在准备一步步地模拟 TList 类, 建立一个自己的 TMyList.

    首先, 这个类中应该包括前面提到的那个 Pointer 数组(TPointerList)的指针(PPointerList):
    TMyList = class(TObject)
      FList: PPointerList;
    end;

    既然是一个列表, 应该有 Count 字段:
    TMyList = class(TObject)
      FList: PPointerList;
      FCount: Integer;
    end;

    TList 类还有一个 FCapacity 字段.

    譬如当前列表中有 10 个元素时, 其实列表已经提前申请出更多位置, 这样就不必每次添加每次申请内存, 从而提高了效率.

    这个 FCapacity 字段就表示已申请的可放置元素位置的总数.
    TMyList = class(TObject)
      FList: PPointerList;
      FCount: Integer;
      FCapacity: Integer;
    end;

    它们都应该是私有的:
    TMyList = class(TObject)
    private
      FList: PPointerList;
      FCount: Integer;
      FCapacity: Integer;
    public
    end;

    应该用属性操作它们:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
    
    type
      TForm1 = class(TForm)
      end;
    {--------------------------------}
      TMyList = class(TObject)
      private
        FList: PPointerList;
        FCount: Integer;
        FCapacity: Integer;
      public
        property Capacity: Integer; {光标放在属性上, 执行 Shift+Ctrl+C, 自动建立属性}
        property Count: Integer;
        property List: PPointerList;
      end;
    {--------------------------------}
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    end.

    自动建立后的属性:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
    
    type
      TForm1 = class(TForm)
      end;
    {--------------------------------}
      TMyList = class(TObject)
      private
        FList: PPointerList;
        FCount: Integer;
        FCapacity: Integer;
        procedure SetCapacity(const Value: Integer);
        procedure SetCount(const Value: Integer);
        procedure SetList(const Value: PPointerList);
      public
        property Capacity: Integer read FCapacity write SetCapacity;
        property Count: Integer read FCount write SetCount;
        property List: PPointerList read FList write SetList;
      end;
    {--------------------------------}
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TMyList }
    
    procedure TMyList.SetCapacity(const Value: Integer);
    begin
      FCapacity := Value;
    end;
    
    procedure TMyList.SetCount(const Value: Integer);
    begin
      FCount := Value;
    end;
    
    procedure TMyList.SetList(const Value: PPointerList);
    begin
      FList := Value;
    end;
    
    end.

    在 TList 中, SetCount 和 SetCapacity 方法都是放在 protected 区以供子类使用, 这里暂时不考虑继承的问题, 就让它们先在 private 区吧;

    不过 List 属性应该是只读的, 它就是那个核心数组的指针, 对它的赋值应该通过更多其他的方法.

    修改如下:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
    
    type
      TForm1 = class(TForm)
      end;
    {--------------------------------}
      TMyList = class(TObject)
      private
        FList: PPointerList;
        FCount: Integer;
        FCapacity: Integer;
        procedure SetCapacity(const Value: Integer);
        procedure SetCount(const Value: Integer);
      public
        property Capacity: Integer read FCapacity write SetCapacity;
        property Count: Integer read FCount write SetCount;
        property List: PPointerList read FList;
      end;
    {--------------------------------}
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TMyList }
    
    procedure TMyList.SetCapacity(const Value: Integer);
    begin
      FCapacity := Value;
    end;
    
    procedure TMyList.SetCount(const Value: Integer);
    begin
      FCount := Value;
    end;
    
    end.

    作为一个列表, 最起码应该有 Add、Delete、Clear 方法.

    Add 方法的参数应该是一个指针(TList 就是存放指针的吗), 如果需要同时返回元素的位置, 应该定义成函数;

    Delete 是删除指定位置上的元素, 参数是个位置号;

    Clear 是清除列表, 对象释放(Destroy)时也应该执行此过程.

    综上所述, 修改如下:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs;
    
    type
      TForm1 = class(TForm)
      end;
    {--------------------------------}
      TMyList = class(TObject)
      private
        FList: PPointerList;
        FCount: Integer;
        FCapacity: Integer;
        procedure SetCapacity(const Value: Integer);
        procedure SetCount(const Value: Integer);
      public
        destructor Destroy; override;         {覆盖父类的 Destroy 方法}
        function Add(Item: Pointer): Integer;
        procedure Clear;                      {在 TList 中这是个虚方法, 以备子类覆盖}
        procedure Delete(Index: Integer);
        property Capacity: Integer read FCapacity write SetCapacity;
        property Count: Integer read FCount write SetCount;
        property List: PPointerList read FList;
      end;
    {--------------------------------}
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    
    { TMyList }
    
    function TMyList.Add(Item: Pointer): Integer;
    begin
    
    end;
    
    procedure TMyList.Clear;
    begin
    
    end;
    
    procedure TMyList.Delete(Index: Integer);
    begin
    
    end;
    
    destructor TMyList.Destroy;
    begin
      Clear;     {在类释放时同时清除列表}
      inherited; {在 TList 中没有这句, 大概是因为它的父类也没什么可继承的}
    end;
    
    procedure TMyList.SetCapacity(const Value: Integer);
    begin
      FCapacity := Value;
    end;
    
    procedure TMyList.SetCount(const Value: Integer);
    begin
      FCount := Value;
    end;
    
    end.

    为了让代码更清晰, 还是把这个类相关的所有代码放到一个独立的单元吧(新建一个单元, 我们把它保存为: MyList.pas).

    因为 MaxListSize、TPointerList、PPointerList 都是在 Classes 单元定义的, 为了省略 uses Classes, 在 MyList 单元中重新做了定义.
    unit MyList;
    
    interface
    
    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);
      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;
      end;
    
    implementation
    
    { TMyList }
    
    function TMyList.Add(Item: Pointer): Integer;
    begin
    
    end;
    
    procedure TMyList.Clear;
    begin
    
    end;
    
    procedure TMyList.Delete(Index: Integer);
    begin
    
    end;
    
    destructor TMyList.Destroy;
    begin
      Clear;
      inherited;
    end;
    
    procedure TMyList.SetCapacity(const Value: Integer);
    begin
    
    end;
    
    procedure TMyList.SetCount(const Value: Integer);
    begin
    
    end;
    
    end.

    至此, 类的轮廓已经出来, 该实现一下这些方法了.
  • 相关阅读:
    数组和对象常用方法汇总
    基于vue的悬浮碰撞窗口(用于打广告的)组件
    时间的基本处理
    防抖动和节流阀
    A. 配置xftp和xshell来远程管理Linux服务器
    课堂练习-找水王
    评价软件
    构建之法阅读笔记02
    学习进度条博客11
    用户场景
  • 原文地址:https://www.cnblogs.com/shijiaoyun/p/3844507.html
Copyright © 2020-2023  润新知