测试你对DELPHI的面向对象了解到什么程度,一个看似简单的现象(200分)

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

jshyhzj

Unregistered / Unconfirmed
GUEST, unregistred user!
//程序中有一行,加不加此行,运行结果不同!
//您能清晰地解释此现象的原因么?
//这是我特意构造的陷阱

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TFun = function: string of object;

TTest = class
public
function getName: string;
procedure testProc;
end;

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
end;


var
Form1: TForm1;

procedure test(AFun: TFun);

implementation

{$R *.dfm}

procedure test(AFun: TFun);
begin
showmessage(AFun);
end;

{ TTest }

function TTest.getName: string;
begin
result := self.ClassName;
end;

procedure TTest.testProc;
begin
test(getName);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
t: TTest;
begin
t:= TTest.Create
//加不加此行,运行结果不同!
t.testProc;
end;

end.
 
用对象之前要TTest.Create创建一个TTest对象.用完还要T.Free;清除对象.
有始有终才能提高效率.有些对象你不创建还会出错.创建了不关闭就一直占用着你的系统资源.
 
t:= TTest.Create
//加不加此行,运行结果不同!
类想使用,就要创建,最后还要FREE
 
题目搞这么大还以为是什么呢,原来..................能不能不忽悠?
 
t:= TTest.Create
//不加此行他自动调用Object类的Create,不知对不对!
 
t:= TTest.Create
//加不加此行,运行结果不同!---------我还以为一样
t.testProc;
若运行结果一样我才觉得希奇
类没有实例化或已实例化运行的结果当然不一样
没有实例化运行不出错才怪,
这个例子好像没有完全理解面向对象的思想
 
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1047021
全面说明了原因
 
to benhacker:
对象不一定非要创建才能调用它的方法,看过这样的语法么:
TMyClass(nil).MyMethod

type
TMyClass = class
procedure MyMethod;
end;

procedure TMyClass.MyMethod

begin
showmessage('出错了么?');
end;

to rastevil:
不会自动调用

to: lah998
你哪个URL错在一个最基础的地方:FREE是一个普通方法,不一定要实例化对象,见我to benhacker的例子。
 
to Supermay
没有实例化对象就调用它的方法是否出错是可以预见的,不是“不出错才怪”

我的MSN签名:
DELPHI: 事件是什么?是属性;方法是什么?是地址;对象是什么?是指针;字符串是什么?哎,说来话长呀
 
to: lah998
我错了,你哪个URL我全部看了,后面的贴子已经把问题解释的很清楚了。后面如果把OP如何实现类方法的多态解释一下就更好了,特别是用类名调用类方法与用对象调用类方法的差异。
 
如果不加那一行,會運行出錯,因為testProc不是TTest的類方法。
樓主的貼子這樣改一改
TTest = class
public
function getName: string;
procedure testProc;virtual;
end;

TChildTest=class(TTest)
end;

procedure TForm1.Button2Click(Sender: TObject);
var
t: TTest;
begin
t:= TTest.Create
//這里Show出來的是TTest
t.testProc

end;

procedure TForm1.Button3Click(Sender: TObject);
var
t: TChildTest;
begin
t:= TChildTest.Create;
t.testProc
//這里Show出來的是TChildTest
end

不奇怪。
 
加时.test.getname中self代表本类即TTEst
不加时,test.getname中self代表窗体Form,即TForm.

其中Test.testProc根本不需要实例化,就可调用,应该没什么疑问,
但 Test.Getname需要实例化吗? result:=self.classname;
本身self.classname调用不需要实例化,所以结果不会出错.但由于self没被初始化,它实际
为现在运行窗体,其类名就为Tform了.
从这里我们可以看出delphi对没实例化的类,当调用时不管怎么不对它都会执行.出错了不关我的事.它只简单初始化一下,这点不同于c++吧.因为delphi编辑器它喜欢包办婚姻.什么事情都要管管.
 
这应该是delphi中最基础的知识了吧,如果连这个都不知道,怎么入门
 
本问题涉及到两个知识点:对象方法的可调用性,未初始化的局部变量的值。

1.严格说来,对象方法在一个已经被创建的对象实例上调用才有意义,当然,如果这个方法中没有用到任何与对象实例有关的东西,那么就会表现得和类方法一样——同样可以被调用,并且不会报错——但这终究是语言规范所不允许的,负责任的程序员应该排除对象未被创建就调用对象方法的情况。

2.楼主的问题中,如果将该行去掉,那么test就是一个未被初始化的局部变量——它的值是不可预测的——不过在这个特定的例子中,test的值就是Sender(见帖子1294954中我的分析),在这种情况下,编译器实际上用Sender充当了test,调用了test的方法——运气好的是,这个方法较为“安全”——没有访问任何局部变量,但是,在调用ClassName的时候,还是暴露了自己的真实身份。
要规范的话,楼主应该将题目改成这样:
var
t: TTest;
begin
t:=nil
//将局部变量初始化为nil
t:=TTest.Create
//加不加此行,运行结果不同!
t.testProc;
t.Free.
end;
现在再运行看看效果? :-)

关于未初始化的局部变量的深入讨论,请看:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=2652090
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1294954 难道对象不需创建就可以使用?
 
我真的没有这样试过,在C#中不能通过的
除外是静态方法
 
这个问题记得以前说过了.
你这个不Create与Create是有区别的为什么呢.
类实例只有在Create之后才会为实例分配内存空间,
1,所以你Create之后显示的正常
2,但是不Create(也就是不初始化)
你这个类的指针指向的是什么地方你知道吗?(我是不知道)它有可能指向
上一个类的实例所分配的内存空间,在这个例子中只是这个指针指向了
TForm类的实例TForm1这个指针所指向的内存空间,所以显示出了TForm1
3,说点多余的,delphi的编译器可能是会把一些过程编译为静态的,也就是
说为什么你在不初始化这个类的实例的情况下也可以调用一些过程的原因.
不知说的对不对,请指教
 
关于这个问题,请参考两篇文章:
《为什么类不用实例化就能访问它的方法》讲述TTest为什么可以不调用Create(),而访问testProc方法:
http://www.01cn.net/users/aimingoo/files/unsafe.method.call.zip

《类方法与对象方法中的Self有什么不同》讲述这个例子中不同的self之间的关系,以及Delphi源码中以nil为self的一些应用:
http://www.01cn.net/users/aimingoo/files/what.is.self.zip

另外,也有一与此类同的,但原因不同的例子在这里:
http://www.01cn.net/cgi-bin/topic_show.cgi?id=467&h=1#3067

另外的一组讨论:
http://www.delphibbs.com/delphibbs/dispq.asp?lid=1047021
 
帮顶!

http://www.source520.com

站长开发推广同盟 站长朋友的终极驿站
同时拥有海量源码电子经典书籍下载

http://www.source520.com/search/search.asp

"编程.站长"论坛搜索引擎-----为中国站长注入动力!
 
to creation-zy
第一点是正确的
第二点:test就是一个未被初始化的局部变量——它的值是不可预测的——不过在这个特定的例子中,test的值就是Sender(见帖子1294954中我的分析),:Sender是Button1

test的值与编译器有关,在调用TForm1.Button1Click(Sender: TObject);时EAX = Form1,DELPHI调用方法时总是用EAX传递SELF的(第一个参数),t.testProc因为前面没有任何代码,EAX的值没有变, test的值是不确定的,编译器总是想象着test在EAX中,这是有道理的,因为只有一个局部变量test,且TForm1.Button1Click(Sender: TObject);中没有使用SELF,既EAX是不需要保存的,调用t.testProc时直接认为EAX就是test,所以直接调用t.testProc,根本没有test -> self(EAX)。即发生前述现象。
 
楼主的贴子我觉得跟这个差不多:
procedure TForm1.Button1Click(Sender: TObject);
var i: integer;
begin
ShowMessage(IntToStr(i));
end;
这样调用一个没初始化的值(准确的来说,是编译器随机定义的值),这样做有意义么?这个属于面向对象的问题?
我只能对楼主的行为感到遗憾。creation-zy在前面已经说了,我就不再说了。

对于连自己也不能控制的代码,不符合最基本的编写原则,有意义么?(当然,你自己可以钻研一下编译器,但这并不属于所谓的程度问题。。)。

PS.有试过这个吗?
procedure TForm1.Button1Click(Sender: TObject);
var
t: TTest;
begin
t.testProc;
t.testProc
//两个
end;
 
后退
顶部