为什么不创建对象实例,仍可以调用方法,这怎么解释?(10分)

  • 主题发起人 主题发起人 Archerfl
  • 开始时间 开始时间
A

Archerfl

Unregistered / Unconfirmed
GUEST, unregistred user!
我的代码:
unit Unit1;

interface

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

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

var
Form1: TForm1;

implementation

{$R *.dfm}

type
TMyClass = class
procedure Test;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
k: TMyClass;
begin
// k := TMyClass.Create;
k.Test;
end;

{ TMyClass }

procedure TMyClass.Test;
begin
ShowMessage('不创建实例,仍可调用!');
end;

end.
如上所示,调试通过,运行正常,加注释那句用不用无所谓。这是为什么呀?
 
it is a static procedure.

so you can call it whenever you create the object.
 
I think it is the same as Class Procedure.
 
这样申明起码是不安全的:
执行后,电脑的内存出现“混乱”。
你可以在k.test;后面添加k.free;
这时,内存“混乱”的症状明显减轻。

一般Delphi不提倡这样做(其实在某个过程中执行申明一个对象,不对其初始化也是可以使用的)
不过,Delphi的自保护功能可能替你做了你没做的事情。
 
DELPHI的异常保护...
 
  楼上很多位提到这是由于Delphi的异常保护功能造成的,不过关于Delphi这方面的资料,
我还没有看到过!
  能否具体说明一下,它到底是如何保护的,那么Delphi还有什么其它的保护形式吗?
 
嗯,,你把Tmyclass申明在另外一个UNIT里有试过么》?
DELPH好像对同一个UNIT中的各类间的调用有点特别。。。。
 
to forss:
   试过了,一样可以。Delphi对同一个Unit中的类调用确实有点特点。不过,那是相对
于对象实例的访问权限来说的!
 
函数过程成员是可以的,如果是数据成员就不行了
 
同意Tuatara。
因为函数成员是无论类实例是否已经创建,都是在内存中实际存在的,因此是可用的,
只要在函数成员中没有关于对类数据成员的操作就行了。
可以这么想象,声明了一个类,就相当于在内存建立了相应的方法和指针,它是一个模板,
但里面的指针都是没有指向合法地址的,所有.Create都是复制这个模板,并申请足够的
内存。
你再做个例子,在myClass中声明一个String成员变量,再声明一个字符数组变量,
当如你的方法,向String成员变量写入时,立即抛出异常(因为立即要申请内存了),
而向字符数组变量写入时,就肯定当时不会发生异常,但你写入的不知道是哪一块地址,
所以可能在其它时候,程序莫明其妙的抛出异常。
 
to szf:
  感谢您的解释!我照您的思路试验了一个,代码调整如下:
unit Unit1;

interface

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

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

var
Form1: TForm1;

implementation

{$R *.dfm}

type
TMyClass = class
s: string;
procedure Test;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
k: TMyClass;
begin
// k := TMyClass.Create;
k.Test;
// k.s := 'abc';
end;

{ TMyClass }

procedure TMyClass.Test;
begin
s := '不创建实例,仍可调用!';
ShowMessage(s);
end;

end.
在类中加一个成员变量s,然后在方法Test中对其进行赋值,这样如上程序调用k.Test没问题的!
可以对s改写,但是我并没有创建类的实例,换句话说,也并没有分配适合存放类中数据成员变量
的内存,为什么还能通过呢?
另外,假如我直接对该数据字段赋值k.s := 'abc';这时在程序退出时会报错,这个正常!因为
并没有创建类的实例!
 
因为Object Pascal对String类型的方法处理是引用、复制方式的,如果一个字串没有初值,
在它第一次赋值时,会为它申请内存,而另一个地方同样地使用它时,会增加它的引用计数,
而对它加减时,可能会复制后处理,或者在原来的内存块上处理,具体看研究一个Object Pascal,
我也弄不清楚,总之,在不同地方使用同一个String变量,可能程序的行为完全不一样。
而程序只要使用了正确的内存,就不会出错了。
你试试,把s改为 array[0..10000] of Char;
然后在Test方法里FillChar(s,100001,#0),保证冲掉了类后面的内存。程序完全不能使用。
 
to szf:
[:)]您说的不错,我也明白您的意思。不过,当s为String类型时,虽然你不给它赋值时,
它不开辟相应的存放字符串的内存空间,但由于本身s是一个指针,它的大小为四个字节,
做为类中的数据字段应该被分配的,例如:你把s改类型为s: Integer;然后把Test过程改

s := 100;
ShowMessage('Good');然后调用它也没问题呀,我想知道这是为什么呢?
 
因为你对这个整数赋值仍然没有超出内存的使用范围
 
to szf:
请您具体解释一下,没有超出内存的使用范围是什么意思呢?
 
其实这个问题并不复杂,试想对类操作的函数,以及类的属性如:TForm1.ClassName
不是一样没定义实例就可以引用
 
to Archerfl:
整数在类定义中已经占了四个字节,你对它赋值,只是对那四个字节的内存操作而已,
既然那四个字节的内存已经存在了,对它操作就完全是合法的了。
至于Tuatara提到的其实是类方法,类方法本来就是定义为类的方法,而通常的类成员
函数则其实是类实例方法。关于类方法在Object Pascal有详细说明,我也不想研究得太深,够用就行了。
我们在这里讨论的其实是把类实例方法当成类方法来使用了,只要象类方法一样来使用
(类方法的使用有限制的),就基本上(但不是绝对)是正常的。
 
后退
顶部