关于对象实例化的一个小问题。想了想,没有想明白。(50分)

  • 主题发起人 白衣书生
  • 开始时间

白衣书生

Unregistered / Unconfirmed
GUEST, unregistred user!
在Unit2 中定义类如下:
uses Dialogs;
type
TMyClass=class
public
procedure ABC;
end;
.....
procedure TMyClass.ABC;
begin
Showmessage('OK');
end;

然后在Unit1做如下操作:
uses Unit2;
procedure TForm1.Button1Click(Sender: TObject);
var a:TMyClass;
begin
a.ABC
//运行时会出现Showmessage('OK')的对话框
end;

我想问的是:为什么TMyClass类不用实例化就能访问它的方法ABC?
按照我的理解应该是这样的调用的:
var a:TMyClass;
a:=TMyClass.Create
//先实例化
a.ABC
//再调用方法
a.Free
//最后释放
-------有什么错误或理解模糊的吗?? 请指点。
 
W

wjsht

Unregistered / Unconfirmed
GUEST, unregistred user!
你的理解是对的
“为什么TMyClass类不用实例化就能访问它的方法ABC?”
不可能吧
除非你把控件拖到窗体上
自动创建了
 
W

wr960204

Unregistered / Unconfirmed
GUEST, unregistred user!
因为不管是实例的方法还是类的方法,都存放于类空间里,只有域变量(成员变量)才存放于实例中。
所以只要你的方法里面没用到实例的成员变量,不用创建实例也可调用成功。因为他是到类的代码空间去执行的。
 

白衣书生

Unregistered / Unconfirmed
GUEST, unregistred user!
to wjsht:
真的是我说的那样的。
你可作个测试。

to wr960204:
多谢。
>>实例的方法还是类的方法,都存放于类空间里。
意思就是说“实例的方法还是类的方法”共用一段内存?还是分别使用的?
这点我不明白。
这上面写的这种情况中,是否子类都可以执行祖先类中的方法而不需要实例化?
 
J

jobsxy

Unregistered / Unconfirmed
GUEST, unregistred user!
白衣书生,你只需这样测试一下就明白为什么了

procedure TForm1.Button1Click(Sender: TObject);
var a:TMyClass;
begin
showmessage(a.ClassParent.ClassName);
end;

a:=TMyClass.Create
//先实例化
showmessage(a.ClassParent.ClassName)
//再调用方法
a.Free
 

白衣书生

Unregistered / Unconfirmed
GUEST, unregistred user!
to jobsxy:
更糊涂了。
为什么没有实例化的对象的父类是 TButtonControl ?
即showmessage(a.ClassParent.ClassName) 显示为 TButtonControl?
 
L

lzhg_kn

Unregistered / Unconfirmed
GUEST, unregistred user!
纯属个人解,不一定正确。
只要有对象的声明,类就会存在于内存。因此你可以调用静态方法,只要你调用的
静态方法没有访问它的域,就不会出错。
 
C

chshanghai

Unregistered / Unconfirmed
GUEST, unregistred user!
好问题, 我顶.
有点同意 lzhg_kn
 
F

foresail

Unregistered / Unconfirmed
GUEST, unregistred user!
白衣书生:
你的錯誤就在於,基礎不扎實.

按照你的代碼,
var a:TMyClass;
就已經創建了對象.
餘下的我不多說了.好好學習基本功吧.
 

白衣书生

Unregistered / Unconfirmed
GUEST, unregistred user!
to foresail:
>按照你的代碼,
>var a:TMyClass;
>就已經創建了對象.
var a:TMyClass
这个不是类型的声明吗?此时难道就创建了对象?
 
J

jobsxy

Unregistered / Unconfirmed
GUEST, unregistred user!
呵呵,这个问题很奇怪,如同你的测试结果一样,明明声明了a:TMyClass,可
showmessage(a.classname)却是TButton,
如果你在
procedure TForm1.Label1Click(Sender: TObject);
var a:TMyClass;
begin
showmessage(a.ClassName);
end;
你又会发现a居然是TLabel类。

由此我有点同意wr960204的说法,所谓a.abc能正常执行可能是被误导了,并不是正确的作法,还是做个测试
type
TMyClass=class
public
vstr:String;
procedure ABC;
end;
.....
procedure TMyClass.ABC;
begin
Showmessage(self.vstr);
end;

然后在Unit1做如下操作:
uses Unit2;
procedure TForm1.Button1Click(Sender: TObject);
var a:TMyClass;
begin
a.vstr := 'ok';
a.ABC;
end;
好象也很正常,可退出时就出错了.....................,其中原由还是高手来给我们讲解讲解。
 

白衣书生

Unregistered / Unconfirmed
GUEST, unregistred user!
jobsxy:
按照你写的代码作了一下,果然是这样。
你的代码中是不是用到了“成员变量”? 这按照wr960204的说法,是不能使用的啊。
 
F

fu_qi_ming

Unregistered / Unconfirmed
GUEST, unregistred user!
好帖.听.
 
L

lu_sam

Unregistered / Unconfirmed
GUEST, unregistred user!
因为你没有写构造及构析啊,实际你调用的只是类的方法!
 
W

wr960204

Unregistered / Unconfirmed
GUEST, unregistred user!
type
TMyClass=class
private
FMsg:String

public
procedure ABC;
end;
.....
procedure TMyClass.ABC;
begin
Showmessage(FMsg);
end;
再按你上面的方式调用就不行了,因为FMsg是成员变量,属于实例的。
所以还是我上面说的,只要不涉及到实例成员变量的方法就可以调用。因为方法是存放于类的空间里的
 
F

foresail

Unregistered / Unconfirmed
GUEST, unregistred user!
>to foresail:
>>按照你的代碼,
>>var a:TMyClass;
>>就已經創建了對象.
>var a:TMyClass
这个不是类型的声明吗?此时难道就创建了对象?

var a:TMyClass 是類型聲明?
那麼 type 是干什麼用的?
 
M

majorsoft

Unregistered / Unconfirmed
GUEST, unregistred user!
下面说说我的看法吧
1.var a:TMyClass
//并没有创建TmyClass对象!!!
不信?你把a:TmyClass作为TForm1的一个成员看看。它是定义了一个指向TmyClass对象的指针/引用。当它作为TForm1的成员时,在对象构造时,初始化为nil,但定义为函数的局部变量时,它并没有初始化为nil,所以导致
请看下面的代码:
unit Unit1;

interface

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

type
Tmyclass=class
public
procedure showMsg;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
a:TMyClass
public
{ Public declarations }
end;

var
Form1: TForm1;
form2:Tform2;
implementation

{$R *.dfm}

{ Tmyclass }

procedure Tmyclass.showMsg;
begin
showmessage('ok');
end;

procedure TForm1.Button1Click(Sender: TObject);
var
a:TMyClass;
begin
application.CreateForm(Tform2,form2);
a.showMsg;
//运行时会出现Showmessage('OK')的对话框,为什么?因为所对象的方法在其类中共享函数段,即使对象没有创建,同样也可以调用其方法。
if assigned(a) then
begin
form2.memo1.Lines.Add('a:'+a.ClassName);// 为什么是显示是Tbutton?看下面的解释
//因为是函数栈的对象,对象引用并没有初始化为nil
form2.memo1.Lines.Add('a'+inttostr(integer(a)))
// 1
end;
form2.memo1.Lines.Add('button1首地址'+inttostr(integer(button1)));//
//1,2结果显示一样的
//说明对象引用/指针在函数栈并没有初始化,此时它指向button1了,
//其实classname函数相当与一个虚函数。
//不信?请看看className的原形:
{
vmtClassName = -44
//Virtual method table entries
vmtMethodTable = -52
//虚拟方法表入口地址

//class function TObject.ClassName: ShortString;
//{$IFDEF PUREPASCAL}
//begin
//Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;
//注意vmtClassName
//end;
//a.classname当然显示为 Tbutton
form2.show;
end;


 
M

majorsoft

Unregistered / Unconfirmed
GUEST, unregistred user!
可以修改下程序把
a:TmyClass作为Tform的一个成员,在窗口对象构造时,初始化为nil,
那么a.showMsg();可以正常执行,为什么?因为ShowMsg是静态方法,编译器根据其(类名)来确定方法的地址,
但下面的
form2.memo1.Lines.Add('a:'+a.ClassName);会出错,因为a.ClassName方法中使用了
Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^;
vmtclassName'就是className方法的入口地址,相当于虚方法,它要根据(实际的对象)来确定要调用的方法。此时,对象并未创建,所以就会出错了。
 
F

foresail

Unregistered / Unconfirmed
GUEST, unregistred user!
To majorsoft:
能讓你解釋出來還真不容易.
我只指出幾點.
1.--->//因为是函数栈的对象,对象引用并没有初始化为nil
前半句正確,後半句似是而非.
var a:TMyClass //確確實實創建了對象,就在你說的"函数栈"里.,創建的同時系統自動調用類的默認constructor.
2.var a:TMyClass 不存在什麼指針的問題,這就是一個對象實體.
3.showmessage是誰的靜態方法? 再說showmessage跟我們討論的根本無關,因為我們程序里調用的是a.ABC,這裡ABC定義成TMyClass的靜態方法了嗎?

怪不得現在有這麼多人哀嘆Delphi程序員工資低.Delphi程序員的水平不高工資怎麼能高?
呵呵,說說而已,別扔板磚.
 
F

foresail

Unregistered / Unconfirmed
GUEST, unregistred user!
補充:這個類比較特殊,它沒有成員變量.所以它的默認構造函數不會出問題.
如果有成員變量,必須自定義一個constructor
 

Similar threads

S
回复
0
查看
948
SUNSTONE的Delphi笔记
S
S
回复
0
查看
769
SUNSTONE的Delphi笔记
S
S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
I
回复
0
查看
662
import
I
顶部