Delphi-维护对对象的自引用 [英] Delphi - Maintaining Self References to an Object

查看:94
本文介绍了Delphi-维护对对象的自引用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看过很多关于对象中"Self"变量的问题和资源,但是每个人的说法都不尽相同.

I've looked at many questions and resources which deal with the "Self" variable in an Object, but everyone says something different.

例如,在以下问题中: Delphi自指针用法

For example, in this question: Delphi Self-Pointer usage

该问题的最高评分答案似乎是错误的. Pointer(Self)不会指向包含它的对象,因此不能用于从对象内部传递引用.

the highest rated answer to the question appears to be wrong. Pointer(Self) does not point to the object which contains it, and cannot be used to pass references from inside the object.

我尝试这样做:

Type
  myobject = class
    PSelf: Pointer;
  End;

Var
  Obj: myobject;

Procedure RunProgram;
Begin
  Obj := myobject.create;
  Obj.PSelf := @Obj;

  //Run the rest of the program
  .
  .
  .

并且在大多数情况下,这种方法效果很好.

and for the most part, this has worked just fine.

我的问题是:这是一种好的编码习惯吗?在程序执行期间,"PSelf"变量是否可以指向该对象?

My question is: is this a good coding practice? Can the "PSelf" variable be expected to point to the object for the duration of the program's execution?

我最近遇到了一个错误,其中"PSelf"已停止指向它包含的对象,并且我想知道对象是否曾经在堆中乱堆,或者内存是否已损坏.

I recently came across a bug where "PSelf" had stopped pointing to it's containing object, and I'm wondering if objects ever get shuffled around in the heap, or whether the memory had been corrupted.

在某些情况下,使用"Self"变量对我不起作用,现在我无法复制它.因此,整个问题毫无意义,就像我使用"PSelf"变量的技术一样.抱歉.

There is some instance in which using the "Self" variable didn't work for me, and now I cannot duplicate it. So this whole question is pointless, as is my technique of using a 'PSelf' variable. Sorry about that.

正如Ken所指出的,上面的链接有一个正确的答案:)

And as Ken pointed out, the link above has a correct answer :)

推荐答案

我认为您误解了Self是什么,以及对象引用在Delphi中的工作方式.

I think you're misunderstanding what Self is, and how object references work in Delphi.

包含类实例的变量已经是指向该对象实例的指针.为了方便起见,Delphi编译器仅允许您省去解引用运算符(^).

A variable containing an instance of a class is already a pointer to that object instance. The Delphi compiler just allows you to leave out the dereference operator (^) as a convenience.

var
  MyObject: TMyObject;  
begin
  MyObject := TMyObject.Create;  // MyObject is now a pointer to an instance of TMyObject
  ...

Delphi还允许在访问对象实例的成员或属性时不使用解引用运算符.同样,以下代码实际上是等效的:

Delphi also allows the shorthand of not using the dereference operator when accessing members or properties of the object instance. Again, the following code is actually equivalent:

MyObj.SomeProperty := SomeValue;
MyObj^.SomeProperty := SomeValue;

Delphi文档:

类类型的变量实际上是引用对象的指针.因此,一个以上的变量可以引用同一对象.与其他指针一样,类类型变量可以保留值nil.但是您不必显式地取消引用类类型变量即可访问其指向的对象.例如,SomeObject.Size:= 100将值100分配给SomeObject引用的对象的Size属性.您不会将其写为SomeObject ^ .Size:=100.

A variable of a class type is actually a pointer that references an object. Hence more than one variable can refer to the same object. Like other pointers, class-type variables can hold the value nil. But you don't have to explicitly dereference a class-type variable to access the object it points to. For example, SomeObject.Size := 100 assigns the value 100 to the Size property of the object referenced by SomeObject; you would not write this as SomeObject^.Size := 100.

Self是一个自动声明的属性,它指向对象的当前实例.换句话说,它在实现该类的代码中自动可用以引用该对象的当前实例.这使您可以拥有同一对象的多个实例:

Self is an automatically declared property that points to the current instance of the object. In other words, it's automatically available inside the code that implements that class to reference the current instance of the object. This allows you to have multiple instances of the same object:

type
  TMyObject=class(TObject)
  private
    FMyInteger: Integer;
    function GetMyInteger: Integer;
    procedure SetMyInteger(Value: Integer);
  published
    property MyInteger: Integer read GetMyInteger write SetMyInteger;
  end;

...
function TMyObject.GetMyInteger: Integer;
begin
  Result := Self.FMyInteger; 

  // Self is implied, so the above line can more simply be written as
  // Result := FMyInteger;
end;

procedure TMyObject.SetMyInteger(Value: Integer);
begin
  if (Value <> Self.FMyInteger) then  // Self is again implied here
    Self.FMyInteger := Value;
end;

var
 MyObjOne, MyObjTwo: TMyObject;
 i, j: Integer;
begin
  MyObjOne := TMyObject;
  // Here, the code inside TMyObject.SetInteger that
  // uses `Self` would refer to `MyObjOne`
  MyObjOne.MyInteger := 1; 

  MyObjTwo := TMyObject;
  // Here, the code in TMyObject.SetInteger would be
  // using the memory in `MyObjTwo` when using `Self`
  MyObjTwo.MyInteger := 2; 
end;        

请注意,Self仅在实现该类的代码中有效 .它在上面的TMyObject.GetMyIntegerTMyObject.SetMyInteger(在我的示例中是唯一实现的代码)中可用且有效,并且始终引用当前实例.

Note that Self is only valid in the code that implements the class. It's available and valid in TMyObject.GetMyInteger and TMyObject.SetMyInteger above (the only implemented code in my example), and always refers to the current instance.

不需要跟踪Self的地址,因为引用该对象实例的变量是 Self在该对象实例的方法中.它仅在该对象的实例内部有效,并且始终引用该对象实例.因此,在您的代码示例中,PSelf只是浪费的空间-myobject已经包含一个指向其自身的指针,并且该指针可以在myobject方法中自动使用:

There's no need to keep track of the addresses of Self, as the variable referencing that object instance is Self inside methods of that object instance. It's only valid inside that instance of the object, and always refers to that object instance. So in your code example, PSelf is just wasted space - myobject already contains a pointer to itself, and that pointer is automatically available in methods of myobject:

type
  myobject = class;   // Now automatically contains a `Self` pointer
                      // available in methods of the class once an
                      // instance is created

var
  myobj: myobject;
begin
  myobj := myobject.Create;  // myobj.Self now is valid in methods of
                             // `myobject`

这篇关于Delphi-维护对对象的自引用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆