zoukankan      html  css  js  c++  java
  • Delphi中的容器类(一)

    Delphi中的容器类
    作者 陈省
      从Delphi 5开始VCL中增加了一个新的Contnrs单元,单元中定义了8个新的类,全部都是基于标准的TList 类。
     

       TList 类
        TList 类实际上就是一个可以存储指针的容器类,提供了一系列的方法和属性来添加,删除,重排,定位,存取和排序容器中的类,它是基于数组的机制来实现的容器,比较类似于C++中的Vector和Java中的ArrayList,TList 经常用来保存一组对象列表,基于数组实现的机制使得用下标存取容器中的对象非常快,但是随着容器中的对象的增多,插入和删除对象速度会直线下降,因此不适合频繁添加和删除对象的应用场景。下面是TList类的属性和方法说明:

        属性描述
          Count: Integer; //返回列表中的项目数
          Items[Index: Integer]: Pointer; default 通过以0为底的索引下标直接存取列表中的项目
        方法类型描述
          Add(Item: Pointer): Integer;//函数用来向列表中添加指针
          Clear;//过程清空列表中的项目
          Delete(Index: Integer);//过程删除列表中对应索引的项目
          IndexOf(Item: Pointer): Integer;//函数返回指针在列表中的索引
          Insert(Index: Integer; Item: Pointer);//过程将一个项目插入到列表中的指定位置
          Remove(Item: Pointer): Integer;//函数从列表中删除指针
       名称类型描述
          property Capacity: Integer;//可以用来获取或设定列表可以容纳的指针数目
          function Extract(Item: Pointer): Pointer;//Extract 类似于Remove 可以将指针从列表中删除,不同的是返回被删除的指针。  
          procedure Exchange(Index1, Index2: Integer); //交换列表中两个指针

          function First: Pointer;;//返回链表中的第一个指针
          function Last: Pointer;// 返回链表中最后一个指针
          function Move(CurIndex NewIndex: Integer);// 将指针从当前位置移动到新的位置

          procedure Pack;// 从列表中删除所有nil指针
          procedure  Sort(Compare: TListSortCompare);//用来对链表中的项目进行排序,可以设定Compare参数为用户定制的排序函数 

      TObjectList 类
        TObjectList 类直接从TList 类继承,可以作为对象的容器。TObjectList类定义如下:  
           TObjectList = class(TList) 
             ...
        public
         constructor Create; overload;
         constructor Create(AOwnsObjects: Boolean); overload;
         function Add(AObject: TObject): Integer; 
         function Remove(AObject: TObject): Integer; 
         function IndexOf(AObject: TObject): Integer; 
         function FindInstanceOf(AClass: TClass; AExact: Boolean = True; AStartAt: Integer = 0):Integer; 
         procedure Insert(Index: Integer; AObject: TObject); 
         property OwnsObjects: Boolean; 
         property Items[Index: Integer]: TObject; default;
     end;

    不同于TList类,TObjectList类的Add, Remove, IndexOf, Insert等方法都需要传递TObject对象作为参数,由于有了编译期的强类型检查,使得TObjectList比TList更适合保存对象。此外TObjectList对象有OwnsObjects属性。当设定为True (默认值),同TList类不同,TObjectList对象将销毁任何从列表中删除的对象。无论是调用Delete, Remove, Clear 方法,还是释放TObjectList对象,都将销毁列表中的对象。有了TObjectList类,我们就再也不用使用循环来释放了对象。这就避免了释放链表对象时,由于忘记释放链表中的对象而导致的内存泄漏。 另外要注意的是OwnsObjects属性不会影响到Extract方法,TObjectList的Extract方法行为类似于TList,只是从列表中移除对象引用,而不会销毁对象。

      

    TObjectList 对象还提供了一个FindInstanceOf 函数,可以返回只有指定对象类型的对象实例在列表中的索引。如果AExact 参数为True,只有指定对象类型的对象实例会被定位,如果AExact 对象为False,AClass 的子类实例也将被定位。AStartAt 参数可以用来找到列表中的多个实例,只要每次调用FindInstanceOf 函数时,将起始索引加1,就可以定位到下一个对象,直到FindInstanceOf 返回-1。下面是代码示意:

      

    var

        idx: Integer;

    begin

        idx := -1;

         repeat

          idx := ObjList.FindInstanceOf(TMyObject, True, idx+1);

           if idx >= 0 then

            ...

         until(idx < 0);

    end;

      

    TComponentList 类

    Contnrs单元中还定义了TComponentList 类,类定义如下:



    TComponentList = class(TObjectList)

        ...

    public

         function Add(AComponent: TComponent): Integer;

         function Remove(AComponent: TComponent): Integer;

         function IndexOf(AComponent: TComponent): Integer;

         procedure Insert(Index: Integer; AComponent: TComponent);

         property Items[Index: Integer]: TComponent; default;

    end;

    注意TComponentList 是从TObjectList类继承出来的,它的Add, Remove, IndexOf, Insert和 Items 方法调用都使用TComponent 类型的参数而不再是TObject类型,因此适合作为TComponent对象的容器。TComponentList 类还有一个特殊的特性,就是如果链表中的一个组件被释放的话,它将被自动的从TComponentList 链表中删除。这是利用TComponent的FreeNotification方法可以在组件被销毁时通知链表,这样链表就可以将对象引用从链表中删除的。   

    TClassList 类

    Contnrs单元中还定义了TClassList类,类定义如下:



    TClassList = class(TList)

    protected

         function GetItems(Index: Integer): TClass;

         procedure SetItems(Index: Integer; AClass: TClass);

    public

         function Add(aClass: TClass): Integer;

         function Remove(aClass: TClass): Integer;

         function IndexOf(aClass: TClass): Integer;

         procedure Insert(Index: Integer; aClass: TClass);

         property Items[Index: Integer]: TClass

           read GetItems write SetItems; default;

    end;

    不同于前面两个类,这个类继承于TList的类只是将Add, Remove, IndexOf, Insert和Items 调用的参数从指针换成了TClass元类类型。  

    TOrderedList, TStack和TQueue 类

    Contnrs单元还定义了其它三个类:TOrderedList, TStack和TQueue,类型定义如下:



    TOrderedList = class(TObject)

    private

        FList: TList;

    protected

         procedure PushItem(AItem: Pointer); virtual; abstract;

        ...

    public

         function Count: Integer;

         function AtLeast(ACount: Integer): Boolean;

         procedure Push(AItem: Pointer);

         function Pop: Pointer;

         function Peek: Pointer;

    end;

      

    TStack = class(TOrderedList)

    protected

         procedure PushItem(AItem: Pointer); override;

    end;

      

    TQueue = class(TOrderedList)

    protected

         procedure PushItem(AItem: Pointer); override;

    end;

    要注意虽然TOrderedList 并不是从TList继承的,但是它在内部的实现时,使用了TList来储存指针。另外注意TOrderedList类的PushItem 过程是一个抽象过程,所以我们无法实例化 TOrderedList 类,而应该从TOrderedList继承新的类,并实现抽象的PushItem方法。TStack 和 TQueue 正是实现了PushItem抽象方法的类, 我们可以实例化TStack 和TQueue类作为后进先出的堆栈 (LIFO)和先进先出的队列(FIFO)。下面是这两个的的方法使用说明: 

    ·                       Count 返回列表中的项目数。

    ·                       AtLeast 可以用来检查链表的大小,判断当前列表中的指针数目是否大于传递的参数值,如果为True表示列表中的项目数大于传来的参数。 

    ·                       对于TStack类Push 方法将指针添加到链表的最后,对于TQueue类Push 方法则将指针插入到链表的开始。

    ·                       Pop返回链表的末端指针,并将其从链表中删除。 

    ·                       Peek返回链表的末端指针,但是不将其从链表中删除。 

      

    TObjectStack和TObjectQueue类

    Contnrs单元中最后两个类是TObjectStack和TObjectQueue类,类的定义如下:

    TObjectStack = class(TStack)

    public

         procedure Push(AObject: TObject);

         function Pop: TObject;

         function Peek: TObject;

    end;

      

    TObjectQueue = class(TQueue)

    public

         procedure Push(AObject: TObject);

         function Pop: TObject;

         function Peek: TObject;

    end;

    这两个类只是TStack和TQueue 类的简单扩展,在链表中保存的是TObject的对象引用,而不是简单的指针。



    TIntList 类

    到目前为止,我们看到的容器类中保存的都是指针或者对象引用(对象引用其实也是一种指针)。

    那么我们能不能在链表中保存原生类型,如Integer,Boolean或者Double等呢。下面的我们定义的类TIntList 类就可以在链表中保存整数,这里我们利用了整数和指针都占用4个字节的存储空间,所以我们可以直接将指针映射为整数。



    unit IntList;

      

    interface

      

    uses

        Classes;

      

    type

        TIntList = class(TList)

         protected

           function GetItem(Index: Integer): Integer;

           procedure SetItem(Index: Integer;

             const Value: Integer);

         public                               

           function Add(Item: Integer): Integer;

           function Extract(Item: Integer): Integer;

           function First: Integer;

           function IndexOf(Item: Integer): Integer;

           procedure Insert(Index, Item: Integer);

           function Last: Integer;

           function Remove(Item: Integer): Integer;

           procedure Sort;

           property Items[Index: Integer]: Integer

             read GetItem write SetItem; default;

         end;

      

    implementation

      

    { TIntList }

    function TIntList.Add(Item: Integer): Integer;

    begin

        Result := inherited Add(Pointer(Item));

    end;

      

    function TIntList.Extract(Item: Integer): Integer;

    begin

        Result := Integer(inherited Extract(Pointer(Item)));

    end;

      

    function TIntList.First: Integer;

    begin

        Result := Integer(inherited First);

    end;

      

    function TIntList.GetItem(Index: Integer): Integer;

    begin

        Result := Integer(inherited Items[Index]);

    end;

      

    function TIntList.IndexOf(Item: Integer): Integer;

    begin

        Result := inherited IndexOf(Pointer(Item));

    end;

      

    procedure TIntList.Insert(Index, Item: Integer);

    begin

         inherited Insert(Index, Pointer(Item));

    end;

      

    function TIntList.Last: Integer;

    begin

        Result := Integer(inherited Last);

    end;

      

    function TIntList.Remove(Item: Integer): Integer;

    begin

        Result := inherited Remove(Pointer(Item));

    end;

      

    procedure TIntList.SetItem(Index: Integer;

         const Value: Integer);

    begin

         inherited Items[Index] := Pointer(Value);

    end;

      

    function IntListCompare(Item1, Item2: Pointer): Integer;

    begin

         if Integer(Item1) < Integer(Item2) then

          Result := -1

         else if Integer(Item1) > Integer(Item2) then

          Result := 1

         else

          Result := 0;

    end;                         

      

    procedure TIntList.Sort;

    begin

         inherited Sort(IntListCompare);

    end;

      

    end.



    扩展TList,限制类型的对象列表  

    Begin Listing Two - TMyObjectList

    TMyObject = class(TObject)

    public

         procedure DoSomething;

    end;

      

    TMyObjectList = class(TObjectList)

    protected

         function GetItems(Index: Integer): TMyObject;

         procedure SetItems(Index: Integer; AMyObject: TMyObject);

    public

         function Add(aMyObject: TMyObject): Integer;

         procedure DoSomething;

         function Remove(aMyObject: TMyObject): Integer;

         function IndexOf(aMyObject: TMyObject): Integer;

         procedure Insert(Index: Integer; aMyObject: TMyObject);

         property Items[Index: Integer]: TMyObject

           read GetItems write SetItems; default;

    end;

    ...

    { TMyObjectList }

    function TMyObjectList.Add(AMyObject: TMyObject): Integer;

    begin

        Result := inherited Add(AMyObject);

    end;

      

    procedure TMyObjectList.DoSomething;

    var

        i: Integer;

    begin

         for i := 0 to Count-1 do

          Items[i].DoSomething;

    end;

      

    function TMyObjectList.GetItems(Index: Integer): TMyObject;

    begin

        Result := TMyObject(inherited Items[Index]);

    end;

      

    function TMyObjectList.IndexOf(AMyObject: TMyObject):

        Integer;

    begin

        Result := inherited IndexOf(AMyObject);

    end;

      

    procedure TMyObjectList.Insert(Index: Integer;

        AMyObject: TMyObject);

    begin

         inherited Insert(Index, AMyObject);

    end;

      

    function TMyObjectList.Remove(AMyObject: TMyObject):

        Integer;

    begin

        Result := inherited Remove(AMyObject);

    end;

      

    procedure TMyObjectList.SetItems(Index: Integer;

        AMyObject: TMyObject);

    begin

         inherited Items[Index] := AMyObject;

    end;

    End Listing Two

  • 相关阅读:
    solaris如何启动ssh服务
    网页实现插入图片—css与html的区别
    Python与RPC -- (转)
    Python中的异常处理 -- (转)
    Python的异常处理机制 -- (转)
    HTML 学习
    链表练习 链表反转 链表插入..
    php解决抢购秒杀抽奖等大流量并发入库导致的库存负数的问题
    PHP队列的实现 算法
    利用redis List队列简单实现秒杀 PHP代码实现
  • 原文地址:https://www.cnblogs.com/carcode/p/2016540.html
Copyright © 2011-2022 走看看