为什么自我可以在Delphi中分配?

时间:2009-05-02 10:00:03

标签: delphi oop language-features self delphi-prism

GUI应用程序中的此代码编译并运行:

procedure TForm1.Button1Click(Sender: TObject);
begin
  Self := TForm1.Create(Owner);
end;

(使用Delphi 6和2009测试)

  • 为什么Self可写而不是只读?
  • 哪种情况有用?

编辑:

  • 在Delphi Prism中也可以吗? (我想是的,见here

更新: 使用Self赋值的Delphi应用程序/库:

5 个答案:

答案 0 :(得分:11)

这并不像它可能那么糟糕。我刚刚在Delphi 2009中对它进行了测试,看起来,虽然Self参数不使用 const 语义,你似乎暗示它应该是,它也不使用 var 语义,因此您可以在方法中更改它,而不会实际丢失调用者对您的对象的引用。那将是一件非常糟糕的事情。

至于原因,两个答案中的一个。要么是简单的疏忽,要么是Marco建议的:允许你将Self传递给 var 参数。

答案 1 :(得分:7)

也许允许传递给const或var参数?

它可能是一个人工制品,因为系统在左边的任何地方都没有自我:= sign。

答案 2 :(得分:4)

分配给自我是如此不合逻辑和无用,以至于这个“特征”可能是一种疏忽。和可分配的常量一样,纠正这些问题并不总是那么容易。

这里简单的建议是:不要这样做。

答案 3 :(得分:2)

实际上,“Self”只是对堆栈中存储指向堆中对象的地址的名称的引用。强制只读这个变量是可能的,显然设计师决定不这样做。我相信这个决定是任意的。

看不到任何有用的情况,只是改变堆栈中的值。此外,更改此值可能很危险,因为无法保证引用实例成员的代码的行为将在编译器版本之间保持一致。

已更新:回复PatrickvL评论

  

'变量'“自我”不在   堆栈(据我所知,它永远不会);   相反,它的价值是放在一个   就在之前注册(准确地说是EAX)   调用任何对象方法。 -

不,自我在记忆中有实际地址。试试这段代码吧。

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(Integer(@Self)));
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  newform: TForm;
  p: ^Integer;
begin
  Self.Caption := 'TheOriginal';
  newform := TForm.Create(nil);
  try
    newform.Caption := 'TheNewOne';
    // The following two lines is, technically, the same as
    //   Self := newform;
    p := Pointer(@Self);
    p^ := Integer(newform);
    ShowMessage(Self.Caption);  // This will show 'TheNewOne' instead of 'TheOriginal'
  finally
    Self.Free; // Relax, this will free TheNewOne rather than TheOriginal
  end;
end;

答案 4 :(得分:1)

有时候,当你想要尽可能地优化方法时(不使用汇编),'Self'可以(ab)用作'free'变量 - 它可能只是意味着它们之间的区别使用堆栈和使用寄存器。

当然,堆栈的内容很可能已经存在于CPU缓存中,因此访问速度应该很快,但寄存器的速度更快。

作为旁注:我仍然错过了我在Amiga的摩托罗拉68000上编程的日子,并且拥有16个数据和16个地址寄存器的奢侈......我无法相信世界选择了限制4个80x86系列处理器的寄存器!

作为最后一点,我有时选择使用Self,因为Delphi的优化器实际上并非优化。 (至少,与在各种LLVM优化器中可以找到的技巧相比,它相形见绌。)恕我直言,当然还有YMMV。