四个button,2个Edit,哪位给讲解一下,我准备了板凳。unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;type
  TForm1 = class(TForm)
    Button1: TButton;
    Edit1: TEdit;
    Edit2: TEdit;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.dfm}procedure TForm1.Button1Click(Sender: TObject);
begin
  Edit2 :=Edit1;
end;procedure TForm1.Button2Click(Sender: TObject);
begin
  FreeAndnil(Edit1);
end;procedure TForm1.Button3Click(Sender: TObject);
begin
  FreeAndnil(Edit2);
end;procedure TForm1.Button4Click(Sender: TObject);
begin
  if Edit1=nil then
    showMessage('Edit1=nil');
  if Edit2=nil then
    showMessage('Edit2=nil');
  if (Edit1 is TEdit) then
    showMessage('Edit1 is TEdit');
  if (Edit2 is TEdit) then
    showMessage('Edit2 is TEdit');
end;end.

解决方案 »

  1.   

    这种写法很 BT 啊
    1。Edit2 :=Edit1; 以后,请问 Edit2 原来的空间怎么得到释放呢?所以,要点击 Button3 后,才能点击 Button1。 
    2。点击 Button1、Button2 后,Edit1 的空间已释放,此时再点击 Button3,将造成对 Edit1 的二次释放,产生错误;而点击 Button4 时,虽然显示 Edit2 还是 TEdit,实际上它的空间已不再有效。你可以在最后加一句:Edit2.text := 'test' 来试试:)
      

  2.   

    看楼主是两星级的,一定是出考题吧!斗胆回答一下:(在原代码基础上加了几句代码)unit Unit1;interfaceuses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;type
      TForm1 = class(TForm)
        Button1: TButton;
        Edit1: TEdit;
        Edit2: TEdit;
        Button2: TButton;
        Button3: TButton;
        Button4: TButton;
        Button5: TButton;
        procedure Button1Click(Sender: TObject);
        procedure Button2Click(Sender: TObject);
        procedure Button3Click(Sender: TObject);
        procedure Button4Click(Sender: TObject);
        procedure Button5Click(Sender: TObject);
      private
        { Private declarations }
      public
        { Public declarations }
      end;var
      Form1: TForm1;implementation{$R *.dfm}var
      P : Pointer;  {首先需要说,此时,作为指针的Edit1、Edit2、P都在全局数据区,各占4个字节(Win32)
      而Edit1和Edit2所指向的对象体,在堆区,为了便于描述,假定如下:
      Edit1 -----> 堆内存块 AAA
      Edit2 -----> 堆内存块 BBB
      此时,AAA和BBB已经在Form1.Create时分配,如果不做任何操作就关闭窗体,则由Form1
      负责回收AAA和BBB
      }procedure TForm1.Button1Click(Sender: TObject);
    begin
      P := Edit2; {暂时保存一下Edit2这个指针值,因为它指向堆内存中的BBB}
      Edit2 :=Edit1; {指针赋值。此时,Edit1和Edit2这两个指针都指向了堆内存中的AAA}
      Edit2.Text := 'abc'; {看一下}
    end;procedure TForm1.Button2Click(Sender: TObject);
    begin
      FreeAndnil(Edit1);
      {此时,AAA已经被释放,并且Edit1的指针值被赋值为nil}
    end;procedure TForm1.Button3Click(Sender: TObject);
    begin
      {如果执行了FreeAndnil(Edit1);再执行下面这句,必然导致一个错误
      因为Edit2也是指向AAA的,而AAA已经释放}
      FreeAndnil(Edit2);
      {如果只执行Edit2 := nil是可以的}
    end;{此时,BBB还没有被释放!幸亏我们用P保存了它的起始地址!}procedure TForm1.Button5Click(Sender: TObject);
    begin
      FreeAndNil(P);
    end;{ 看了前面的,后面的就不用解释了}procedure TForm1.Button4Click(Sender: TObject);
    begin
      if Edit1=nil then
        showMessage('Edit1=nil');
      if Edit2=nil then
        showMessage('Edit2=nil');
      if (Edit1 is TEdit) then
        showMessage('Edit1 is TEdit');
      if (Edit2 is TEdit) then
        showMessage('Edit2 is TEdit');
    end;end.
      

  3.   

    Edit1,Edit2都是对象指针,改了指针的值,实际的存储空间还在。
      

  4.   

    PS:上面注释是假定按 Button1--> Button2 --> Button3 ---> Button5 ---> Button4的顺序Click的
      

  5.   

    我在二楼的注释中有一部分应该改一下:
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      FreeAndnil(Edit1);
      {此时,AAA已经被释放,并且Edit1的指针值被赋值为nil}
      {但是,此时Edit2的值并不是nil,尽管它所指向的AAA已经被释放}
    end;procedure TForm1.Button3Click(Sender: TObject);
    begin
      {如果先执行FreeAndnil(Edit1);再执行下面这句,必然导致一个错误
      因为Edit2此时不是nil,但它指向的AAA已经释放
      如果先执行FreeAndnil(Edit2);则Edit1和Edit2同时变为nil,
      因为:在Edit2 := Edit1的赋值的时候,不仅仅是指针值的赋值,同时Edit2作为了Edit1的“引用”!
      因此,先执行下面这句,再执行FreeAndnil(Edit1);就不会出错了}
      FreeAndnil(Edit2);
    end;
      

  6.   

    edit2:=edit1;释放了edit1再释放edit2就出错了。这么理解对不对?
      

  7.   

    哈哈,谢谢大家关注!
    TO:1L,不变态能引起讨论吗?
    我觉得EDIT1,EDIT2都是对象的指针(OOP叫实例吧,但本质是指针)而已,指向一个Tedit类型的空间。
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      Edit2 :=Edit1;
    end;
    后,Edit2指向EDIT1所指向的地址,此时原来EDIT2的地址没有保存,丢失了。
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      FreeAndnil(Edit1);
    end;
    后,Edit1指向的TEDIT类实例释放,同时EDIT1赋值Nil,EDIT2也是指向了一个不存在的实例,但没有置nil.此时:
    procedure TForm1.Button3Click(Sender: TObject);
    begin
      FreeAndnil(Edit2);
    end;
    出错。
    procedure TForm1.Button4Click(Sender: TObject);
    begin
      if Edit1=nil then
        showMessage('Edit1=nil');
      if Edit2=nil then
        showMessage('Edit2=nil');
      if (Edit1 is TEdit) then
        showMessage('Edit1 is TEdit');
      if (Edit2 is TEdit) then
        showMessage('Edit2 is TEdit');
    end;
    应该显示消息'Edit1=nil'
               'Edit2 is TEdit'因为其没置nil.
    而表现在程序窗口上,虽然Edit2指向了其它地址,但是原来所建立的TEDIT类没有释放,所以在主窗口上EDIT2还是存在的。
    我理解的不对的地方欢迎指正。
      

  8.   

    既然楼主已经开始公布标准答案,那就请教一下:为什么FreeAndNil(Edit2)会将Edit2、Edit1的指针值都置为nil
    而FreeAndNil(Edit1)只能将Edit1置为nil?Delphi又是怎么实现这个的?
      

  9.   

    不知道,没研究过!
    procedure TForm1.Button1Click(Sender: TObject);
    var a,b:TEdit;
    begin
      a :=Edit1;
      b :=a;
      freeandnil(b);
      if a=nil then
        showmessage('a is nil');
      if b=nil then
        showMessage('b is nil');
    end;
    这个只有b是nil;
    procedure FreeAndNil(var Obj);
    var
      Temp: TObject;
    begin
      Temp := TObject(Obj);
      Pointer(Obj) := nil;
      Temp.Free;
    end;
    应该不是FreeAndNil造成的,应该和RTTI有关。
      

  10.   

    FreeAndNil的源代码就摆在这里,有啥好研究的?
    procedure FreeAndNil(var Obj);
    var
      Temp: TObject;
    begin
      Temp := TObject(Obj);
      Pointer(Obj) := nil;
      Temp.Free;
    end; 测试一下就知道了,测试的结果说明一切。
      

  11.   

    to 伴水:再看看....11楼提出的问题....有了答案,贴在这里也可,在QQ上给我留言也可......谢了....害您老晚饭没吃安顿..
      

  12.   

    其实是delphi的语法把指针的概念都弱化了,而且如下的语句编译都通过,且效果一样.Type
      PRecData = ^TRecData;
      TRecData = record 
        Str : string;
      end;var
      P:PRecData;
    begin
      try
        new(P);
        P.Str  := 'aaa'; //以下2句
        P^.Str := 'bbb'; //
      finally
        Dispose(P);
      end;
    end;
      

  13.   

    其实开始一直没有看明白题目,还是昨天和lihuasoft一起调试代码才搞明白问题。当碰到这个问题的时候,我头晕了一阵。真是出现了很多星星。看看释放元件的堆栈:
    TComponent.SetReference(False)
    TComponent.RemoveComponent(...)
    TComponent.Destroy
    TControl.Destroy
    TWinControl.Destroy
    TObject.Free
    ...总结:设计期间创建的元件,即存在窗体资源(.dfm)中的元件,当这类元件被释放的时候,相应的窗体字段也会被赋值为空。
    详细过程参考TComponent.SetReference()方法。楼主可以结贴了。
      

  14.   

    看来,只要细心慢慢找,大多数(不是全部)问题的答案都在VCL源码中。谢谢Zswang负责任地给本贴延伸的第二个问题以完美的答案。同时,这第二问题解决后,也证明我在5楼的某些说法是不恰当的(想多了),楼主原问题的答案应回归2楼。^_^
      

  15.   

    谢谢zswang 来讲课,受用了。
      

  16.   

    其实楼主在12楼已经猜到了,,,“和RTTI有关”