现在准备建立 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 < ) 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 < ) 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 ; type
  PPointerList = ^TPointerList;
  TPointerList = array[..MaxListSize - ] 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 + );
  FList^[FCount] := Item;
  Result := FCount;
  Inc(FCount);
end; procedure TMyList.Clear;
begin
  SetCount();
  SetCapacity();
end; procedure TMyList.Delete(Index: Integer);
begin
  if (Index < ) or (Index >= FCount) then
    raise Exception.CreateFmt('非法的 Index:%d', [Index]);
  if Index < FCount then
    System.Move(FList^[Index+], 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 < ) 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), )
  else
    for i := FCount - downto Value do
      Delete(I);
  FCount := Value;
end; function TMyList.GetItems(Index: Integer): Pointer;
begin
  if (Index < ) or (Index >= FCount) then
    raise Exception.CreateFmt('异常:%d', [Index]);
  Result := FList^[Index];
end; procedure TMyList.SetItems(Index: Integer; const Value: Pointer);
begin
  if (Index < ) 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[];
    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  := ;
  ListA.Add(@r1);   r2.name := '李四';
  r2.age  := ;
  ListA.Add(@r2);   r3.name := '王五';
  r3.age  := ;
  ListA.Add(@r3);   r4.name := '孙六';
  r4.age  := ;
  ListA.Add(@r4);   r5.name := '候七';
  r5.age  := ;
  ListA.Add(@r5);   {获取第三个元素}
  //r := TMyRec(ListA.List^[2]^);          {这是以前的代码}
  r := TMyRec(ListA[]^);
  ShowMessageFmt('%s:%d',[r.name, r.age]); {王五:33}   {删除第三个元素后再访问第三个元素}
  ListA.Delete();
  //r := TMyRec(ListA.List^[2]^);          {这是以前的代码}
  r := TMyRec(ListA[]^);
  ShowMessageFmt('%s:%d',[r.name, r.age]); {孙六:44}   {现在通过 Items 属性, 不仅可以取值, 还可以赋值}
  ListA[] := @r1;
  r := TMyRec(ListA[]^);
  ShowMessageFmt('%s:%d',[r.name, r.age]); {张三:11}   ListA.Free;
end; end.

学习 TList 类的实现[8]的更多相关文章

  1. 学习 TList 类的实现[4]

    现在准备一步步地模拟 TList 类, 建立一个自己的 TMyList. 首先, 这个类中应该包括前面提到的那个 Pointer 数组(TPointerList)的指针(PPointerList): ...

  2. 学习 TList 类的实现[1]

    最近整理了一些函数列表, 算是一个宏观的安排; 等以后再碰到一些函数时就可以放置的更有次序一些. 我对函数与类的理解是: 函数是一个功能模块, 类是一个更强大的功能模块; Delphi 已经提供了很多 ...

  3. 学习 TList 类的实现[2]

    我原来以为 TList 可能是一个链表, 其实只是一个数组而已. 你知道它包含着多大一个数组吗? MaxListSize 个!MaxListSize 是 Delphi 在 Classes 单元定义的一 ...

  4. 学习 TList 类的实现[6]

    实现 TMyList.Add 函数. TList 中的 Add 函数用到了一个 Grow 方法, 它的原理是元素越多就为以后准备更多内存, 我们这里省略为预留 4 个元素的内存; TList 中的 A ...

  5. 学习 TList 类的实现[5]

    先来实现 TMyList.SetCapacity. 马上会想到下面代码: procedure TMyList.SetCapacity(const Value: Integer); begin   if ...

  6. 学习 TList 类的实现[3] - 不能回避的话题: 内存分配

    在 Delphi 中, 几乎所有的类型都有对应的指针类型, 譬如: Char PChar Word PWORD Double PDouble TPoint PPoint 甚至一种类型对应这着几种指针类 ...

  7. 学习 TList 类的实现[7]

    总结目前 TMyList 已具备的功能(3 个方法.3 个属性): Add: 添加; Delete: 删除; Clear: 清空;Count: 元素总数;Capacity: 已存在的所有元素位置数;L ...

  8. Java虚拟机JVM学习07 类的卸载机制

    Java虚拟机JVM学习07 类的卸载机制 类的生命周期 当Sample类被加载.连接和初始化后,它的生命周期就开始了. 当代表Sample类的Class对象不再被引用,即不可触及时,Class对象就 ...

  9. Java虚拟机JVM学习04 类的初始化

    Java虚拟机JVM学习04 类的初始化 类的初始化 在初始化阶段,Java虚拟机执行类的初始化语句,为类的静态变量赋予初始值. 在程序中,静态变量的初始化有两种途径: 1.在静态变量的声明处进行初始 ...

随机推荐

  1. 【Android】3.9 覆盖物功能

    分类:C#.Android.VS2015.百度地图应用: 创建日期:2016-02-04 一.简介 百度地图SDK所提供的地图等级为3-19级(3.7.1版本中有些部分已经提供到了21级),所包含的信 ...

  2. C++ Dll 编写入门

    一.前言 自从微软推出16位的Windows操作系统起,此后每种版本的Windows操作系统都非常依赖于动态链接库(DLL)中的函数和数据,实际上 Windows操作系统中几乎所有的内容都由DLL以一 ...

  3. Python 2.7.9 Demo - 003.01.只允许相同缩进

    Right #!/usr/bin/python if True: print ("True"); print('Again'); else: print ("False& ...

  4. Zookeeper运维的一些经验[转]

    Zookeeper是一个分布式协调框架,有不错的性能,也经过许多公司的验证,所以在很多场景都有使用.大家一般用Zookeeper来实现服务发现(类似DNS),配置管理,分布式锁,leader选举等.在 ...

  5. C++面向对象程序设计的一些知识点(4)

    摘要:累继承可以实现源代码重用,模板技术也可以达到同样的目的.模板可以分为函数模板和类模板,其共同点是允许参数类进行类型化,编译器根据程序员传递的具体类型,又把函数模板实例化为具体函数,把类模板实例化 ...

  6. struts2请求两次即action方法执行两次

    如果方法使用get开头,也会出现重复执行问题....对struts2无语!!! [转]http://www.xuebuyuan.com/301066.html 就把get开头的方法修改了一下,程序就运 ...

  7. 翻转数字最后n位

    #include<stdio.h> int turn_n(int ,int); int main(void) { ,b=; printf("%x\n%d\n%x\n", ...

  8. mongodb常见管理命令

    ----------1.复制数据库 wind:PRIMARY> show dbs; jinri 0.078GB local 1.078GB test 0.078GB wind 0.078GB w ...

  9. Android修改默认SharedPreferences文件的路径,SharedPreferences常用工具类

    import android.app.Activity; import android.content.Context; import android.content.ContextWrapper; ...

  10. Ubuntu之命令壁纸