Delphi:传递引用还是传递值?

15

在Delphi中,如果我有一个简单的类myClass并将其实例传递给一个带有myFunction (myClass)的函数,该函数由function myFunction(myObject:myClass):Boolean定义...

  • 是否会创建myObject的副本?

  • 当我在myFunction中调用myObject的方法时,原始对象是否也会受到影响和修改?

答案:
  • 不会,与原始对象相同的指针将被传递。

  • 是的,因为您拥有对原始对象的指针,并可以修改它。

4个回答

27

对象按引用传递。不会创建副本;只会有一个类的实例,只有一个对象。原始对象就是全部内容。


1
真让人遗憾,你抢先一步了... :) +1 - Marjan Venema
7
是的,原始对象完全存在于堆上。但是除非你通过引用传递,否则你会得到一个引用的拷贝。在这种情况下,你会得到一个指向对象的引用的引用。 - Wouter van Nifterick
函数呢?它们是按引用传递的吗?我看到有人在函数参数中使用了@myProc。 - Noumenon

17

在 Delphi 中,对象是指向堆内存上的数据结构的特殊指针。当您将一个对象传递给一个函数时,实际上传递的是指针,而不是整个对象数据的副本。在这种情况下,通过该引用修改字段或属性将影响原始对象数据。以下是一个简单的示例,演示了这种行为:

program ObjParamTest;

type
  TMyClass = class
  private
    FMyField : Integer;
  public
    property MyField : Integer read FMyField write FMyField;
  end;


function ModifyObject(AnObj: TMyClass);
begin
  AnObj.MyField := AnObj.MyField + 1;
end;  

var
  MyObj : TMyClass;
begin
  MyObj := TMyClass.Create;
  try
    AnObj.MyField := 2;
    Writeln(AnObj.MyField); // ==> Prints 2
    ModifyObject(MyObj);
    Writeln(AnObj.MyField); // ==> Prints 3
  finally
    MyObj.Free;
  end;
end.

需要注意的是,参数修饰符(例如Var、Const、Out)仅改变对象引用传递给函数的方式,对原始数据结构没有影响。

也许这篇文章能更清楚地解释在Delphi中不同的参数传递方式:

Delphi中不同的函数参数修饰符 (存档版本)


1
我同意Mick的观点,你的文章非常值得一读。不过,我认为在发布文章之前,在这里简短、直接地回答问题会更有益处。特别是因为它没有详细讨论按值传递对象和按var传递对象之间的区别。 - Francesca
谢谢,我在帖子中添加了一个简短的描述和一个简单的示例。 - vcldeveloper
1
虽然所有答案在技术上都是正确的,但我认为这个对OP最有帮助。 - Lieven Keersmaekers
AnObj in main body should be changed to MyObj - Vassilis

8
“对象是按引用传递”的含义比这要多一些。对象是引用类型,因此默认情况下始终通过引用传递。任何对象变量都是对象引用。
但是,如果您将一个对象变量“按引用”(作为var参数)传递,则如果您在传递到的例程中替换对象为不同的对象,则在例程返回时会得到不同的对象。在执行此操作时要小心;如果更改对某个对象的唯一引用,则可能会导致内存泄漏。

3
当你说“用另一个对象替换对象”时,实际上指的是“用对另一个对象的引用替换对对象的引用”。你无法用另一个对象替换对象本身,但你可以随心所欲地覆盖引用。 - Rob Kennedy
1
@Rob,你们两个都是对的,因为普遍将“Object”称为引用TObject的变量是一个错误的叫法... MyForm.Width是持有MyForm变量引用的窗体的真实宽度。你改变了MyForm变量,MyForm.Width就是另一个窗体的宽度。因此,“你最终会得到一个不同的对象”在实践中有些描述了程序员的现实。 - Francesca

5

对象是按引用传递的。


只是一个附注:当你使用VAR传递字符串时,它们也是通过引用传递的。 - Gabriel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接