我创建了一个简单的类来解释我的问题:
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上阅读了一些关于类的文章,但仍然找不到我的错误。
答案 0 :(得分:5)
你忽略了实例化这个类。
全局类引用变量初始化为nil
,而局部变量根本没有初始化。局部变量的值由您调用函数时堆栈上的任何内容确定,并且您的程序正在解释该值,就好像它是TTest
引用一样,即使它实际上并非如此。然后,您的程序将读取该内存地址的值,以获取代表val
字段的值。
您的代码似乎与非全局变量一起使用的唯一原因是运气。无论是好运还是坏事都是另一回事。 (祝你好运,因为你的代码似乎工作正常,而且工作代码总是很好。运气不好,因为如果你的代码崩溃了,你早些时候就会被警告你的错误。)
在使用对它的引用之前实例化一个类。
x := TTest.Create;
现在,您可以通过x
变量访问对象的字段,方法和属性。
当您尝试使用局部变量而不首先为其赋值时,您应该已经获得编译器警告。虽然它们只是警告,并且您的程序仍然会运行,但永远不要忽略警告甚至提示。当编译器不愿抱怨某事时,通常是正确的。
答案 1 :(得分:3)
在Delphi中,对象变量总是指针。在使用变量之前,需要使用对象的引用对其进行初始化。最常见的方法是创建特定类的新对象。
procedure Foo;
var
Obj: TObject;
begin
Obj := TObject.Create;
try
// Do stuff with Obj
finally
Obj.Free;
end;
end;
在这种情况下,Obj以未初始化的指针开始(它将指向随机存储器)。只有在我们分配新创建的TObject之后,Obj才是有效的对象引用。
在Delphi中,对象没有自动垃圾收集,因此在使用它们时总是需要对它们进行免费调用。如果声明全局或局部对象变量,则可以将其初始化为单元的特殊初始化部分,并在完成部分中释放该对象。
unit myunit;
interface
var
Obj: TObject;
implementation
initialization
Obj := TObject.Create;
finalization
Obj.Free;
end.
在接口部分中声明的变量是全局可见的,在实现部分中声明的变量仅在单元内可见。应该注意的是,声明全局对象变量意味着任何单元都可以通过引用新对象来覆盖变量,而不必先释放现有对象。这会导致内存泄漏,因为没有自动垃圾收集。
答案 2 :(得分:0)
delphi类基本上只是一个描述,而不是对象本身。您将描述最终对象应具有的属性和方法。这个难题的缺失部分是你没有真正告诉Delphi从你的班级创建一个对象。
这是通过调用构造函数来完成的:
mMyInstance:=TTest.Create;
构造函数接受类描述并在内存中为您构建对象实例。它返回一个指向对象的指针,该对象必须存储在相同类型的变量(上例中的myInstance)中。
阅读你的问题,我怀疑你想创建一个“永远存在”的对象,有点像打印机对象。这很容易做到,但就像打印机对象一样 - 在访问对象之前必须包含该单元。我认为上面的Anders E. Andersen已经展示了大多数人如何从单位中心角度初始化对象。
如果您希望可以从其他单位(例如您的主窗体或任何其他单位)访问该对象,请先将“myunit”添加到使用列表中。然后为了使它可见,你添加一个函数,如下所示:
function test:ttest;
Begin
result:=obj;
end;
请记住将“function test:TTest”添加到设备的接口部分。然后你可以使用其他单位的对象:
myUnit.test.get;
但要注意!这是相当古老的学校编程,在你完成其他单位之前,你冒着你的单位被释放的风险(它会调用终结并因此摧毁你的对象)。因此,您可能会冒险在内存中不再存在的对象中调用函数 - 在程序关闭时导致严重的访问冲突。
如果您想正确学习Delphi,请转到Delphi Basics并阅读基本原则。学习一门新语言需要一段时间,但你很快就会掌握它。
祝你好运!