我创建了一个简单的类来解释我的问题:
ttest =class
private
val:boolean;
published
function get:boolean;
end;
...
function ttest.get: boolean;
begin
val:=not val;
result:=val;
end;
现在,如果我声明一个局部ttest变量并调用my_var.get;然后一切都正常,但如果我将其声明为全局变量,那么它就不能再访问val字段,它会显示一条错误消息,上面写着"访问违规…"。我读了一些关于Delphi中类的文章,但仍然没有发现我的错误。
您忽略了实例化类。
全局类引用变量初始化为nil
,而局部变量根本不初始化。局部变量的值由调用函数时堆栈上发生的任何事情决定,程序将该值解释为TTest
引用,尽管它实际上不是。然后,您的程序读取该内存地址的值,以获得表示val
字段的值。
代码使用非全局变量的唯一原因是运气。运气好还是坏是另一回事。(祝你好运,因为你的代码似乎可以工作,而且工作代码总是很好的。祝你运气不好,因为如果你的代码崩溃了,你会更早地被提醒你的错误。)
在使用对类的引用之前实例化它。
x := TTest.Create;
现在,您可以通过x
变量访问对象的字段、方法和属性。
当您尝试使用局部变量而不首先为其赋值时,应该会收到编译器警告。尽管它们只是警告,并且您的程序仍将运行,但永远不要忽略警告甚至提示。当编译器不厌其烦地抱怨某件事时,通常是对的。
在Delphi中,对象变量总是指针。在使用变量之前,您需要使用对对象的引用对其进行初始化。最常见的方法是创建特定类的新对象。
procedure Foo;
var
Obj: TObject;
begin
Obj := TObject.Create;
try
// Do stuff with Obj
finally
Obj.Free;
end;
end;
在这种情况下,Obj一开始是一个未初始化的指针(它将指向随机内存)。只有在我们分配了新创建的TObject之后,Obj才是有效的对象引用。
在Delphi中,对象没有自动垃圾收集,所以在使用完它们后,您总是需要对它们调用free。如果声明全局或局部对象变量,则可以在单元的特殊初始化部分对其进行初始化,并在最终确定部分释放对象。
unit myunit;
interface
var
Obj: TObject;
implementation
initialization
Obj := TObject.Create;
finalization
Obj.Free;
end.
在接口部分中声明的变量是全局可见的,在实现部分声明的变量仅在单元内部可见。需要注意的是,声明全局对象变量意味着任何单元都可以用对新对象的引用覆盖变量,而无需首先释放现有对象。这将导致内存泄漏,因为再次没有自动垃圾收集。
delphi类基本上只是一个描述,而不是对象本身。您描述了最终对象应该具有的属性和方法。缺少的一点是,您并没有真正告诉Delphi从您的类中创建一个对象。
这是通过调用构造函数来完成的:
mMyInstance:=TTest.Create;
构造函数获取类描述,并在内存中为您构建一个对象实例。它返回一个指向对象的指针,该对象必须存储在相同类型的变量(上例中为myInstance)中。
读到你的问题,我怀疑你想创建一个"永远存在"的对象,有点像打印机对象。这很容易做到,但就像打印机对象一样——在访问对象之前,必须包含该单元。我认为Anders E.Andersen已经展示了大多数人如何从以单元为中心的角度初始化对象。
如果你想从另一个单元(比如你的主窗体或任何其他单元)访问对象,首先在使用列表中添加"myunit"。然后,为了使其可见,您添加了一个函数,如下所示:
function test:ttest;
Begin
result:=obj;
end;
记住在单元的接口部分添加"函数测试:TTest"。然后你可以使用另一个单元的对象,例如:
myUnit.test.get;
但请注意这是非常老派的编程,在其他单元完成之前,你的单元就有被释放的风险(这会调用终结,从而破坏你的对象)。因此,你有可能调用内存中不再存在的对象中的函数,当你的程序关闭时,会导致严重的访问违规。
如果你想正确地学习Delphi,请访问Delphi基础知识并阅读基本原理。学习一门新语言需要一段时间,但你很快就会掌握窍门
祝你好运!