难道对象不需创建就可以使用?或是Delphi的Bug?????(50分)

下面的程序sender在哪里?
program Project1;
{$APPTYPE CONSOLE}
uses SysUtils;
type
TMyObject=class
private
x:integer;
public
procedure print();
end;
//类使用,下面的代码运行并无错误,是何道理????
var
MyObject:TMyObject;
procedure TMyObject.print();
begin
write(x);
end;
begin
// MyObject:=TMyObject.Create;
MyObject.print;
end.
 
to:dirk

Why???
procedure TForm1.Button1Click(Sender: TObject);
var
ss:TEdit;
begin
TButton(ss).Caption :='哈哈哈';
end;
 
to eski:
我很奇怪,你说你给的代码运行并无错误,我想你应该真正运行过,但在我这里,的确是
出错了的:
Exception EAccessViolation in module Project1.exe at 00008638.
Access violation at address 00408638 in module 'Project1.exe'. Read of address 0
0000004.
 
看看这些代码:
procedure ad;
var
ss:tedit;
begin
ShowMessage(ss.ClassName );
end;

procedure TForm1.CheckBox1Click(Sender: TObject);
begin
ad;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
ad;
end;

虽然 ad 过程没有参数,但你能在程序中让一个过程的整个调用过程中没有Sender参数吗?
不管嵌套多少层,第一个过程肯定有Sender:TObject参数,所以,在delphi的程序中,对象
即使不创建,一样可以用,不过是Sender罢了,这个参数会向被它调用的过程传递。
对于绝对没有Sender参数的调用,也有,就像eski的例子:
program Project1;
{$APPTYPE CONSOLE}
uses SysUtils,stdctrls,Dialogs;
procedure ad;
var
ss:tedit;
begin
ShowMessage(ss.ClassName );
end;

begin
ad
end.

但肯定出错,因为,对象真的没有被创建,当然出错,对不存在的地址的访问,怎么可能
不错?对这点,你用身上任何一个部位想想都知道(开个玩笑,没有恶意 ;) ),一个
你认为没有创建的对象被正确访问了,那只表明一件事,它是存在且被创建了的,关键是,
它是谁?我告诉你,它就是Sender!
 
to:dirk
不要太自信,測試一下我給你的代碼吧.變成Form.Caption,不是Sender

Why???
procedure TForm1.Button1Click(Sender: TObject);
var
ss:TEdit;
begin
TButton(ss).Caption :='哈哈哈';//變成Form.Caption,不是Sender
end;
 
to dirk:
>>那我的说法也没有错:在delphi中,这个没有create的对象其实就是Sender!
>>但你能在程序中让一个过程的整个调用过程中没有Sender参数吗?
>>不管嵌套多少层,第一个过程肯定有Sender:TObject参数

你走火入魔了,怎么研究这个东西?!而且没有Sender的例子多的是!
子线程的函数有Sneder吗?消息响应函数有Sender吗?在程序启动时调用
的初始化函数有Sender吗?
而且你的研究已经偏离正道了,退一万步说,就算你说的正确,但是,你
用的是什么版本?你能保证换一个版本正确吗?你能保证在换一个编译参数
还正确吗?(比如你把优化这个编译参数关掉)
更重要的是,你那样编出来的算是合格程序吗?即使结果正确,恐怕代码检
查是绝对通不过的。没有任何可读性!!
>>你认为没有创建的对象被正确访问了,那只表明一件事,它是存在且被创
>>建了的,关键是,它是谁?我告诉你,它就是Sender!
而且这句话也不对,即使象你说的那样,没有创建的对象依然没有被创建,绝
对不可能,也只能说“你认为没有创建的对象被正确访问了,那只表明一件事,
它是存在的。它是谁?我告诉你,它被指向了Sender!”因为在Delphi中,所有的
~~~~~~~~~~~(永远不会被创建,我以我的人头担保)
类实例,都是一个引用,和C++的引用类似,在语法上,用法和变量一样,但是
实际上是用指针实现的。如果我们学习过编译原理角度,学过汇编,就很好理解
这个问题,更不会朝dirk所说的方向去解释-即使dirk说的没错,也是由于编译器
的缘故,比如,编译器可能把未初始化的对象在编译的时候,优化指向成某个寄存器
的值、或堆栈的值,而该值恰恰是Sender,如果有的话!
 
to dirk:
chenghus所说的那段代码不知是否正确,如果那样的话,你就无论从理论上
还是实际上,你都错误了。对于你的说法,我不想象chenghus那样从代码上
找出你的错误,没有任何实际意义,不知道你是怎么发现这个问题的,怎么
会有这样的看法?奉劝你一句,多看看基础理论知识,研究你那个(?门?道)
没有意义!
 
To SS2000:
交流交流,找出問題是為了解決問題,多談談問題的Why?
 
Faint! 无量劫以前就被详细的剖析过的问题。
调用时,只是使用了内存Class信息中的VMT表的信息,并将对象本身作为一个参数传递给
这个过程,如果方法本身没有访问对象的任何实例数据,不报错当然是可以理解的。相反,
如果过程中访问了对象的数据,此时的对象就是一种未初始化的指针,没有人能够保证不会
出问题。

更深入的基础知识,请看 http://www.delphibbs.com/delphibbs/dispq.asp?lid=0506986
其中:
bbkxjy:
因为 TObject 的 Create 方法是空的,什么都没做,那么,对象
实例占用的内存,及初始化是在那里完成的呢?这个魔法是由编译器暗地里实现的,
在生成的机器码中,在进入TObject.Create前,编译器自动生成了调用
TObject.NewInstance 的代码,NewInstance 会调用 GetMem 分配内存,跳到
TObject.InitInstance对这块内存进行初始化,然后返回该内存地址作为结果,
即对象变量实际上是指向这块内存的指针。


我和楼上的大哥观点一样——研究这种和“未初始化”相关的问题是毫无意义的,还不如
找本书深入的研究Delphi的对象机制。
 
To: creation-zy,SS2000
請各位幫忙,關注一下我的問題,可要實際測試!!!
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1290762
 
to chenghus:
>>交流交流,找出問題是為了解決問題,多談談問題的Why?
既然你这么说,我就试了试你的代码和dirk的代码,我发现,只有我新开一个
工程来测试你们的代码,才不会出错。如果我用我已有的工程来测试(已存在
Form,上面已经有了很多控件,很多代码),你们写的所有代码统统出错!!
非法地址访问等等乱七八糟的错误!!!
dirk,还有必要讨论你的那个说法吗?
chenghus,我已经解释了问题的原因,你还有什么地方不清楚?
 
本来,这只是对一个问题的讨论,但现在看了SS2000的话,我有点生气了,虽然我早就听
人说过,delphibbs的人,大多容不得反对的发言,现在我也遭遇到了,请问,什么叫“走
火入魔”、“偏离正道”?难道,对一个奇怪的现象进行研究、发表自己的见解是“走火入
魔”、“偏离正道”?那么什么又是你所说的“正道”?对一个奇怪、自己不理解的现象,
就应该对自己说:“让它去吧!”,这才不会“走火入魔”、“偏离正道”?真是气愤,研
究问题也会被人莫名其妙攻击!

我又没有说所有的都一定有Sender,但没有Sender的地方,你去引用没有创建的对象,肯定
要出错的,就像eski的程序一样,肯定出错!

“指向了Sender”和“就是Sender”我认为没有什么本质的区别,Sender是什么?也就是个
指针,“它是存在且被创建了的”,也没有什么不对,它是存在的,难道它不是被创建的?
只是不是在这个过程中被创建的,难道我要这么说才能不被你钻?

我想你的“人头”大概真的要落地了,如果我也和你一样钻研别人的每个用字的话:
>>(永远不会被创建,我以我的人头担保)
永远不会被创建?你是想告诉我们,delphi中真的可以不创建对象而引用它!对此,我只
确信一点:delphi中,绝对不可能使用一个没有创建的对象,这和C++不同(当然C++和
delphi不同,不用Create,但对象在定义时也被创建了的),在delphi中,你不Create这
个对象,就没有它在内存中的位置,就不可能被使用!难道我这么说也错吗?

你总是说:巧合、恰恰,什么叫巧合、恰恰?难道Borland就是通过这些巧合来保证delphi
编制的程序稳定、健壮地运行的吗?我敢保证,你在一个Button的OnClick事件中定义一个
局部对象变量,而不创建它,当你引用它时,它100%就是Sender!如果真的100%是这样(请
你证明这个没有创建的对象什么时候不是Sender!),你又怎么还能说,这只是“恰恰”?!

我仍然这么认为:一个你认为没有创建的对象被正确访问了,那只表明一件事,它是存在且被
~~~~~~ ~~~~
创建了的,关键是,它是谁?我告诉你,它就是Sender!
~~~~~~

chenghus,你所说的现象我早就知道了,只是我对它的理解还不确定,所以没有发言,但是,
你这样用:
procedure TForm1.Button1Click(Sender: TObject);
var
ss:TEdit;
begin
TButton(ss).left:=0;
TButton(ss).top:=0;
end;
你绝对看不到Form被移到屏幕的左上角,而是Button1!
 
原来你还没试过这些代码,我也不明白为什么非要用一个新项目,我在一个正在做的项目
进行测试,根本没错,这个form上有50多个控件,很少吗?

我用的是Delphi5.0。
 
to dark:
我绝对没有说容不得反对的发言,我只是指出你的错误,这么看来是你
容不得反对的发言了。
既然你也知道chenghus所说的现象,为什么还要“它100%就是Sender”呢
~~~~
>>你总是说:巧合、恰恰,什么叫巧合、恰恰?难道Borland就是通过这些巧合来保证delphi
>>编制的程序稳定、健壮地运行的吗?
你在说我吗?我觉得是你是通过这些巧合来保证delphi编制的程序稳定、健壮地运行的吗。
因为我绝对不会用没有初始化的变量,而且也绝对不允许别人这么用(当然,这个人必须
是我手下,如果是你我就管不着了)。
我只是指出了你的错误,如果你不服气,而且因此生气,那我就闭嘴就是,不再对你的
见解发表任何评论和看法。(如果有些词伤害了你,向你致歉)
我是欢迎你对我的看法和见解作任何评论。



 
创建了对象系统才会分配地址,你什么都没有调用,当然没事,如果调用对象的变量
,就会找不到地址.
 
sorry!

我今天的火气也大了!

你知道我看到你说的话的感觉吗?你说:“你走火入魔了,怎么研究这个东西?!”
我没有走火入魔,这个现象是我在另一个关于其它问题的帖子中看到的,有个人说这样可以,
我不信,因为我认为没有创建的对象是不可能被使用的,试了一下,居然可以,所以,自己
研究了一下,上面的就是我的看法,这难道就值得被认为是“走火入魔”?我气!如果你是
要指正我的看法的错误,请说好了,我非常欢迎,但你那样的话,实在很无聊,令人生气!

对于chenghus的现象,我的解释:
chenghus,你所说的现象我早就知道了,只是我对它的理解还不确定,所以没有发言,但是,
你这样用:
procedure TForm1.Button1Click(Sender: TObject);
var
ss:TEdit;
begin
TButton(ss).left:=0;
TButton(ss).top:=0;
end;
你绝对看不到Form被移到屏幕的左上角,而是Button1!

我不想说我也不确认的东西,但你运行上面的例子,难道ss还有可能是Form吗?

我也绝对不会用没有初始化的变量,而且也绝对不允许别人这么用(当然,这个人必须
是我手下,如果是你我就管不着了),但是对于这个现象,我只是想知道,why?

我也是欢迎你(任何人)对我的看法和见解作任何评论,但请讨论问题,不要说那些无聊
的话,我到这里只是想和人讨论问题,而不是想在这里和什么人吵架!

如果言语有冒犯,请原谅,人总有火气大的时候!
 
研究你永远不可能在实际中应用的东西是毫无意义的(至少在编程方面)——我只能这么说了。

to dirk兄:
var
ss:TEdit;
begin
TButton(ss).left:=0
//在此处设置断点,运行,点击Button1,然后Ctrl+Alt+L
TButton(ss).top:=0;
end;
——你看到了什么?—— ss:([csInheritable],false,false)
双击它,你就会看见:ss:TEdit ebx ——ebx!!!都是编译器的“优化”在起作用。
(还有: Name: Button1)

——这样的代码是绝对不符合最基本的编程原则(注意,不是“规范”)的,您会在编译
时得到一行警告: Variable "ss" might not have been initialized.
——一个合格的程序应该没有任何警告。再说,应该没有人会认为这种用法有实用价值。


另:
如果我们把Project - Options - Compiler - Optimization 选项关闭,再次编译运行
的话,再上述的断点处按下Ctrl+Alt+L,就会看到: ss:([],false,fase), 双击之,可以
看到:ss: TEdit $12F5DC ——这下未初始化的对象终于“现形”了!接着单步运行之,
我们就会很容易的得到 EAccessViolation 错误。
——没有这个“尚方宝剑”,我还真是说服不了一些同道,看来还要努力呀!

对于任何编程方面的疑问,都应该从原理上加以透彻的了知,而不是在看到了表面现象
之后就以为自己“知道了”。当我们无法从一个层面上解释某种现象的时候,就应该深入
这个现象之后,从更加深层的机制进行突破。——一切现象都是有原因的,编程语言也是
一样的。


附上汇编代码:
var //打开编译优化 watch: TControl(eax) TControl(ebx) ss
ss:TEdit;
begin //1.push ebx Form1 Button1 ebx(Button1)
//2.xor edx,edx 为SetLeft过程准备参数
//3.mov eax,ebx 将ss送至eax——编译器认为ss已经被置于ebx
Button1 Button1 Button1
ss.Left:=0
//4.Call TControl.SetLeft 调用TControl(ss).SetLeft(0)过程
//实际上就是调用 TControl(Button1).Setleft(0)
ss.Top:=0
//...
end;
在上面的begin处设置断点,就会发现此时的ebx,edx均指向Button1。edx指向Button1可以
理解——它就是Sender。那么ebx呢?我认为是Delphi在前面的procedure TControl.Click;
过程的遗留问题(没办法跟进去,只能“认为”了,555...)。如果我们在ss.Left之前加上
一句“ss:=nil;”,再次查看汇编代码,我们就会发现Delphi只是1、2句之间插入了一句
“xor ebx,ebx”——显然,在打开编译优化的情况下,Delphi认为局部变量ss是被存放在
寄存器ebx中的,编译器不会主动为它赋值或清零,除非你用代码进行初始化。因此,在dirk
的代码中,ebx的内容就是Button1。如果我们在begin和ss.Left之前加入一个比较复杂的
运算(例如:Form1.Caption:='123'+IntToStr(Tag);),那么ebx就会被改变成一个很难
把握的值,经过这个运算,ebx和Button1的关系自然就被打破了——“没有Create的对象
其实就是Sender”这个现象的原因找到了!
 
就事论事,其实一个未初始化的变量,特别是指针,我们如果用C语言
编过程序,就知道,很多时候死机都是指针使用不当,特别是未初始化。
但是这些错误很难查,为什么,因为错误莫名其妙,而且有时候有,有
时候没有。也就是说,指针未初始化并不一定出错,而是随机的。在Delphi
中也一样,也是随机的。就象我测试的,新开的工程,使用未初始化的
对象,不出错,而且确实是Sender,但在我的旧工程中就死机,出错,成随
机性,如果不信我可以把我的工程发给你们自己试,所以,使用未初始化的
对象,什么事情都可能发生,当然包括指向Sender
 
TButton CheckBox 等Standard都是从windows标准类继承来的,本身具有他们的个性东西

----------------------------------------------
TMyObject=class 表示是个类,类方法的调用是不用Create的,且方法只能
独立运行, 也可理解为该类不过是函数的集合。
相当与
class function Test: ShortString;
定义


 
为什么这里的人说话,都喜欢用“毫无意义”、“一个头脑正常的程序员”之类的词来形容
别人?我想,没有人听到这样的话会欣欣然的。还有,我也申明,不是“争论”,我不想和
什么人“争论”,我希望是“讨论”,有什么好争呢?就事论事讨论嘛!

还有,我再重申,我绝不会在程序中这样使用,干吗都说的好像我是这么在编程似的?

对于变量的初始化,我一直也有个疑问,你们编程时,对于局部定义的普通变量都是进行初始
化的吗?就像这样:

procedure TForm1.Button1Click(Sender: TObject);
var
i:integer;
begin
i:=0;
i:=i+1;
edit1.Text :=inttostr(i);
ShowMessage(inttostr(i));
end;

如果把i:=0这句去掉,程序有错吗(C++?)?但是,编译时,有时会出现:
[Warning] Unit1.pas(32): Variable 'i' might not have been initialized
有时不会,出现时,i的值就是个错误的值,不出现时,i就是0,这又怎么说?
当然,上面的程序在实际中也没有上面什么意义,当然也就没有什么必要再讨论了!

算了,没什么再想说什么的了!creation-zy在这里也是个高手,和你“争”“意义”
(如果他这样认为)是没有什么好处的。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
D
回复
0
查看
1K
DelphiTeacher的专栏
D
I
回复
0
查看
580
import
I
顶部