在类TList的属性
property Items[Index: Integer]: Pointer read Get write Put; default;
的写方法中用到了这样一个方法:
procedure TList.Put(Index: Integer; Item: Pointer);
var
  Temp: Pointer;
begin
  if (Index < 0) or (Index >= FCount) then
    Error(@SListIndexError, Index);
  if Item <> FList^[Index] then
  begin
    Temp := FList^[Index];
    FList^[Index] := Item;
    if Temp <> nil then
      Notify(Temp, lnDeleted);
    if Item <> nil then
      Notify(Item, lnAdded);
  end;
end;
上面的Notify来源是类TList的一个方法,
 procedure Notify(Ptr: Pointer; Action: TListNotification); virtual;
但实现代码代码里面什么也没做,请问编译器到底隐藏了什么?(查帮助也没有)

解决方案 »

  1.   

    就是问类TList的Notify方法到底做做了什么?是销毁变量、回收内存吗?
      

  2.   

    看了又看,只是看到上面这段程序在程序起动的时候执行,并且我还发现Fcount=3,感觉像是在初始化信息。
      

  3.   

    楼上的不是这个意思,Put是属性Items[Index: Integer]的写方法,
    好像这样:
    var
      List:TList;
      item:Pointer ;
    begin
      List:=TList.Create;
      List.add(Item);
      item:=... 
      .....
      {下面改变FList^[Index]的值}
      List.item[index]:=item
      {这里就调用了PUT方法}
    end;
      

  4.   

    我觉得可以从Tlist继承下来。只要就可以override这个方法,就可以转换成事件驱动。
      

  5.   

    上面代码有问题,大概就哪个意思,
    在Put里先判断下标是否越界,没有的话再看值有没有改变,如有改变,把旧指针取出来放到Temp 中再放入新指针到数组里去,但搞不懂这个Notify做了什么。
      

  6.   

    我想下面这个过程
    procedure TList.Notify(Ptr: Pointer; Action: TListNotification);
    begin
      //编译器一定是做了一些工作
    end;
      

  7.   

    是啊,我就是问做了什么工作,查了帮助,没有这个类的,其他类倒有:
    TCollection.NotifyResponds when items are added to or removed from the collection.type TCollectionNotification = (cnAdded, cnExtracting, cnDeleting);
    procedure Notify(Item: TCollectionItem; Action: TCollectionNotification); virtual;DescriptionApplications can抰 call the protected Notify method. It is called automatically when the items in the collection change.Item is the item that was just added to or that is about to be removed from the collection.
      

  8.   


        TList.Notify确实“什么都没做”,但它并非是“没有用”(不仅又想起了关于TObject.DefaultHandler的那场讨论来了),它是留给你进行override的。
        
        至于具体操作,你可以参看一下TObjectList和TInterfaceList的实现,它们都override了这个方法,以便正确地释放List中的对象/接口。
      

  9.   

    编译器可能不需要做什么工作,Notify 是一个虚的方法,由后代类来实现。
    如果 TList 的后代类在插入或删除一个元素后,需要特殊的处理,则后代类可以实现这个 Notify 方法,在这个方法中进行处理。如果不需要处理,则可以不用实现这个方法。
    Notify 纯粹是为了方便后代类。
      

  10.   

    用保留字vritual声明的方法,虚方法是实现对象多态性的基本机制
    这样的方法保存在虚方法地址表(VMT)(对象类的虚方法地
    址表(VMT – Vritual Method Table)中,
    如果你search一下,就会发现此方法广泛存在于Classes类中,但参数不同,不过作用大同小异吧,不过在我看来,
    TList.就像一个dbgrid 而TCollection(随便一个)就象stringgrid了
    dbgrid没有fixcol属性,但stringgrid有,要想使dbgrid具备fixcol那就要进行强制转换
    也就是说假如dbgrid也有fixcol属性,但只是没有具体实现而要让用户通过其后代类进行实现
    达到同属于dbgrid但能有不同效果的作用,也就是多态了在要不就是borland为了和别的类相呼应,加了这么个东西,其实完全没用,^_^
      

  11.   

    其实你看效果就行了,notify没有代码,也就是不执行任何操作,但只有pointer 和action两个属性,好像是要告诉类在put的时候现删除后增加,如果没有此代码 效果会怎么样呢??
    但TCollection也有此方法,但有操作,也就是说.......
      

  12.   

    其实这种上级父类在这里使用了自己定义的一些没有实现的方法,但对于派生类来说,他继承了PUT方法,而且派生类也有可能覆盖了NOTIFY方法,这样一来,当派生类执行PUT的时候实际上NOTIFY就是有内容的,所以这里只是为派生类提供一个扩展接口,没有什么特别的....
      

  13.   

    谢谢大家,最初把Controls当成了Contnrs单元,所以总是找不到其派生类TObjectList在哪里,照样做个总结:
    我们知道,虚方法、抽象方法、接口都能实现多态(是否接口才是真正意义上的、更为广泛的多态);对于类的抽象方法,在类本身没有任何实现,所以也不能创建基于抽象类的实例;虚方法可以有实现,也可以什么都不做(就像上面),具体的实现留给其派生类去处理;对于接口,在接口类里声明的方法需要支持接口的类去实现;
    对于上面的问题,其实我最大的疑问还不在这里,我在想,这个类的NOTIFY方法是在TLIST里被调用的即使其派生类覆盖了该方法,那么在TLIST的PUT里能调用到其派生类的方法吗?
    后来看了TObjectList,明白了原因所在:
    再看一看下面的代码:
    procedure TList.Put(Index: Integer; Item: Pointer);
    var
      Temp: Pointer;
    begin
      if (Index < 0) or (Index >= FCount) then
        Error(@SListIndexError, Index);
      if Item <> FList^[Index] then
      begin
        Temp := FList^[Index];
        FList^[Index] := Item;
        if Temp <> nil then
          Notify(Temp, lnDeleted);
        if Item <> nil then
          Notify(Item, lnAdded);
      end;
    end;
    如上我们知道对于类方法(或对象方法)来说,其中有隐藏了一个代表对象本身的SELF参数上面的代码实际上是这样的:
    procedure TList.Put(Index: Integer; Item: Pointer);
    var
      Temp: Pointer;
    begin
      with self do
      begin
      ......
      end;
    end;
    这样的话,当其派生类调用PUT时就是调用的派生类的PUT方法,同样NOTIFY也就是派生类的NOTIFY,所以自然没有问题。
      

  14.   

    补充上面,当派生类调用PUT时,这个SELF代表派生类。
      

  15.   


      重要的不再于self,而在于Notify是个虚函数,可以被衍生类override,所以才能完成“在基类中调用衍生类的方法”的任务。