实现 TMyList.Add 函数.
TList 中的 Add 函数用到了一个 Grow 方法, 它的原理是元素越多就为以后准备更多内存, 我们这里省略为预留 4 个元素的内存;
TList 中的 Add 函数还同时触动了一个 Notify 方法, 这应该是为它们的子类准备的(估计是用它来激发一个事件的), 也不要了.
TList 中的 Add 函数用到了一个 Grow 方法, 它的原理是元素越多就为以后准备更多内存, 我们这里省略为预留 4 个元素的内存;
TList 中的 Add 函数还同时触动了一个 Notify 方法, 这应该是为它们的子类准备的(估计是用它来激发一个事件的), 也不要了.
function TMyList.Add(Item: Pointer): Integer; begin {如果预申请的内存用完了, 再申请够 4 个元素用的} if FCount = FCapacity then SetCapacity(FCapacity + 4); {Add 是添加在最后面, 把指针赋予数组} FList^[FCount] := Item; {函数返回} Result := FCount; {元素总数 + 1} Inc(FCount); end;
再实现 TMyList.Delete 过程.
同前, 把错误处理也简化成一个异常; 也省略了对 Notify 方法的触动.
其中用到了 System.Move, 可以参考: http://www.cnblogs.com/del/archive/2008/03/27/1126226.html
这里有一个问题是需要高度注意的: TList 在删除一个元素(它的元素就是指针)时, 并没有释放指针指向的对象, 只是从列表开除;
如果要同时 Free 掉对象, 应该使用 Contnrs 单元下的 TObjectList 类.
procedure TMyList.Delete(Index: Integer); begin {如果给的 Index 不符合要求, 就抛出异常} 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)); {总数 - 1} Dec(FCount); end;
还要实现 TMyList.SetCount 方法.
之前我没有想到 Count 属性还是可写的; 这可够狠的, 譬如已经有 100 个元素, 如果让 Count := 1; 这一下就要删除后面 99 个元素!
还有不理解的是: 譬如已经有 100 个元素, 如果让 Count := 200; 那后面的 100 个元素即便是填充了空字符, 用指针读过来也不是对象啊? 觉得不妥. 不过暂时也这样了.
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;
还有一个 TMyList.Clear 方法.
因为不用考虑列表中对象释放的问题, 这个就简单多了.
procedure TMyList.Clear; begin SetCount(0); SetCapacity(0); end;
至此, 已经声明的方法都实现了, 这个 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); 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 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; end.