我认为您误解了Self
Delphi 中的对象引用是什么以及对象引用的工作方式。
包含类实例的变量已经是指向该对象实例的指针。为了方便起见,Delphi 编译器只允许您省略取消引用运算符 ( ^
)。
var
MyObject: TMyObject;
begin
MyObject := TMyObject.Create; // MyObject is now a pointer to an instance of TMyObject
...
Delphi 还允许在访问对象实例的成员或属性时不使用取消引用运算符的简写。同样,以下代码实际上是等效的:
MyObj.SomeProperty := SomeValue;
MyObj^.SomeProperty := SomeValue;
从德尔福文档:
类类型的变量实际上是一个引用对象的指针。因此,不止一个变量可以引用同一个对象。像其他指针一样,类类型变量可以保存值 nil。但是您不必显式取消引用类类型变量来访问它指向的对象。例如, SomeObject.Size := 100 将值 100 分配给 SomeObject 引用的对象的 Size 属性;你不会把它写成 SomeObject^.Size := 100。
Self
是一个自动声明的属性,指向对象的当前实例。换句话说,它在实现该类的代码中自动可用,以引用对象的当前实例。这允许您拥有同一对象的多个实例:
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.GetMyInteger
它在及以上(我的示例中唯一实现的代码)中可用且有效TMyObject.SetMyInteger
,并且始终引用当前实例。
无需跟踪 的地址Self
,因为引用该对象实例的变量位于该对象实例的方法 Self
内部。它仅在该对象的实例内有效,并且始终引用该对象实例。因此,在您的代码示例中,PSelf
只是浪费了空间-myobject
已经包含一个指向自身的指针,并且该指针在以下方法中自动可用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`