create过程中参数的问题 (50分)

  • 主题发起人 主题发起人 j5203
  • 开始时间 开始时间
J

j5203

Unregistered / Unconfirmed
GUEST, unregistred user!
一个类的create过程的参数(比如self,application等)是表示这个类的所有人是谁,
并且这个类是由他的所有人释放的。

由他的所有人释放是什么意思--我们什么语句都不用写,所有人会自动释放???
那么为什么还在destroy过程中加上一句TXXX.Free手动释放。
写控件的时候,若控件中又用了别的控件,比如Timer,这个Timer的Create参数用的
就是self,但这个控件(Timer的所有人)在Destory过程中仍然要加上一句FTimer.Free。
这又是为什么呢?


如果必须在destroy过程中加上一句TXXX.Free手动释放的,那么我们在
create过程中指定self,application还有什么意义呢?

 
有意思的问题,刚才看了些相关的VCL源码

Create(AOwner: TComponent) 的最终代码在
TComponent.Create(AOwner: TComponent) 里面,
代码很简单.


>>由他的所有人释放是什么意思--我们什么语句都不用写,所有人会自动释放???
>>那么为什么还在destroy过程中加上一句TXXX.Free手动释放。

如果你 create 了一个新的button,并且它的owner是你的Form,那么完全不需要
在Form的destroy过程中手动free你的button.

至于为什么,呵呵,去看看TComponent.Destroy的代码,再结合刚才的,你的问题
就不再是问题了
 
写了几行程序,可以测着玩玩儿,你会发现如果先free了myButton1,也就是
myButton2的Owner,调用myButton2的Click方法是会报错的。

这说明myButton2此时也已经被 free 掉了

procedure TForm1.Button1Click(Sender: TObject);
var myButton1:TButton;
myButton2:TButton;
begin
myButton1 := TButton.Create(form1);
myButton2 := TButton.Create(myButton1);
myButton2.Caption := 'hello';
// myButton1.Free;
// myButton1 := nil;
myButton2.Click; // myButton2并没有Click事件,不过并不影响这个过程本身的执行
end;
 
但在写控件的时候,若控件中又用了别的控件,比如Timer,这个Timer的Create参数用的
就是self,但这个控件(Timer的所有人)在Destory过程中仍然要加上一句FTimer.Free。
这又是为什么呢?
 
加一句 FTimer.Free 应该只是起个心理安慰作用。

在 TComponent.Destroy; 里,我们能看到对 DestroyComponents 这个方法的调用,
而 DestroyComponents 作了些什么呢?

procedure TComponent.DestroyComponents;
var
Instance: TComponent;
begin
while FComponents <> nil do
begin
Instance := FComponents.Last;
if (csFreeNotification in Instance.FComponentState)
or (FComponentState * [csDesigning, csInline] = [csDesigning, csInline]) then
RemoveComponent(Instance)
else
Remove(Instance);
Instance.Destroy;
end;
end;

可以看出是将自身维护的一个Components的列表中每一个元素都销毁,而
这些元素正是当它们在create时被加入这个列表的。
 

我从前也是一直惦记着自己创建的东西要自己负责销毁,但现在来看好像不是
这么一回事。

我参考的是Delphi6的源码,不知道以前的版本是不是作了不一样的处理
 
但如果你创建了如TStringList,TStrings,TRegistry,TIniFile等没有Owner的对象(不是TComponent)
的话,还是要自己释放的,还有如New操作,也需要调用dispose去释放。
有时使用如下语句:
MyForm:=TMyForm.Create(nil);
此时也要记着释放
 
要是我就搂着她不放,看系统能把我怎么样!!??
 
很遗憾,以下程序在Delphi6中并不报错。
procedure TForm1.Button1Click(Sender: TObject);
var myButton1:TButton;
myButton2:TButton;
begin
myButton1 := TButton.Create(form1);
myButton2 := TButton.Create(myButton1);
myButton2.Caption := 'hello';
myButton1.Free;
myButton2.Click; // myButton2并没有Click事件,不过并不影响这个过程本身的执行
end;
 
to j5023
你的以上程序未指定myButton1 and myButton2 的parent 属性
两个button 在form1上现实不出了
 
To j5203
在你第二段代码里,你能告诉我,这两各按钮的 Owner 是谁?
不要想当然地回答,你需要仔细考究准了再回答。
 
第二段不是我写的呀。不过按照我的理解,应该是myButton1的owner是Form1
myButton2的owner是myButton1
 
那段程序当然没有错,因为没有事先free myButton1 啊,你看下面呢

procedure TForm1.Button1Click(Sender: TObject);
var myButton1:TButton;
myButton2:TButton;
begin
myButton1 := TButton.Create(form1);
myButton2 := TButton.Create(myButton1);
myButton1.Free;
myButton1 := nil;
myButton2.Click; // myButton2并没有Click事件,不过并不影响这个过程本身的执行
end;

另外在这个例子里button能不能显示出来不是关键
 
天哪,我也是被此类问题困扰,参加讨论.我自己写了一个ActiveX控件,
把它放在一个form2(form1为mainform)上面.控件上面有一个button1.
我想用控件上面的button1关闭form2并且把form2. free掉.
但是试了好多方法都不能成功.最后只能在button1加代码DestroyWindow(self.parentwindow)
但也是只能hide窗体,并没有释放掉.不信你可以试试看.重新form2create,再Destroy就报错,
因为系统找不到唯一的form2.handle.
 
To j5203
对啊,你都知道啊。就是下面:
procedure TForm1.Button1Click(Sender: TObject);
var myButton1:TButton;
myButton2:TButton;
N1,N2:String;
begin
myButton1 := TButton.Create(form1);
myButton2 := TButton.Create(myButton1);
myButton2.Caption := 'hello';
myButton1.Free;
// myButton2.Click;

N1:=myButton1.Owner.ClassName;
N2:=myButton2.Owner.ClassName;
MessageBox(Handle,PChar(N1+';'+N2),'Owner Name',mb_Ok);
end;

再试试下面:
procedure TForm1.Button1Click(Sender: TObject);
var myButton1:TButton;
myButton2:TButton;
begin
myButton1 := TButton.Create(form1);
myButton2 := TButton.Create(myButton1);
myButton2.Caption := 'hello';
myButton1.Free;
Try
myButton2.Caption := 'olleh';//Click;
except
On EInvalidPointer do
MessageBox(Handle,'错啦错啦,你指到哪里去了?','无效指针',mb_Ok);
end;
end;
 
那段sample程序是我写的,小雨哥你想说什么?我不是很明白阿
 
To Cheka:
我是说就按下面的写法写,他也不会出错。
procedure TForm1.Button1Click(Sender: TObject);
var myButton1:TButton;
myButton2:TButton;
begin
myButton1 := TButton.Create(form1);
myButton2 := TButton.Create(myButton1);
myButton1.Free;
myButton1 := nil;
myButton2.Click; // myButton2并没有Click事件,不过并不影响这个过程本身的执行
end;

另外,有趣的是,小雨哥第二段程序必须是按钮按三次才会出错。

 
如果,是继承了父类的控件是不用释放的,比如在
type
TForm1 = class(TForm)
内的就不用释放。
如果是自定义的或动态的就要在适当时释放或destroy。
 
用个更简单的例子说明问题吧

procedure TForm1.Button1Click(Sender: TObject);
var myButton1:TButton;
myButton2:TButton;
begin
myButton1 := TButton.Create(form1);
myButton2 := TButton.Create(myButton1);

myButton1.Free;
myButton2.Free;
end;

看看会不会出错。
 
那当然会出现错误了,,没有你的父亲哪来你呀
 
后退
顶部