【问题标题】:Why Delphi XE3 gives "E2382 Cannot call constructors using instance variables"?为什么 Delphi XE3 给出“E2382 无法使用实例变量调用构造函数”?
【发布时间】:2012-10-08 20:05:12
【问题描述】:

我有一段简单的代码,它在 Delphi XE2 中编译,但在 XE3 中不编译,我不知道为什么。我已将有问题的代码减少到一点点,并想知道 Delphi 认为它有什么问题。尝试在 Delphi XE 2 中编译包含此单元的项目工作正常,但在 Delphi XE3(试用版)中,它给出“[dcc32 Error] AffineTransform.pas(26): E2382 Cannot call constructors using instance variables”。我在这里知道的唯一“古怪”的事情是使用老式的“对象”类型,其中构造函数与真实对象(基于 TObject 的类实例)中的构造函数并不完全相同。

如果我将这个对象中的“constructor”替换为“procedure”,那么它可以编译,但是为什么会这样,在我的代码中这是一个可以做的改变吗?对功能的影响?

unit AffineTransform;

interface

type
  { Rectangular area. }
  TCoordRect = object
  public
    Left, Top, Right, Bottom: Real;
    constructor CreatePos(ALeft, ATop, ARight, ABottom: Real);
    procedure   Include(AX, AY: Real);
  end;

implementation

constructor TCoordRect.CreatePos(ALeft, ATop, ARight, ABottom: Real);
begin
  Left := ALeft;
  Top := ATop;
  Right := ARight;
  Bottom := ABottom;
end;

procedure TCoordRect.Include(AX, AY: Real);
begin
  CreatePos(AX, AY, AX, AY)
end;

end.

【问题讨论】:

  • 为什么要在遗留的 Turbo Pascal 对象上实现构造函数?那应该是一个过程,它应该被称为Initialize
  • @LaKraven 没有继承的 Create。这是object 而不是class
  • 没有发现,@DavidHeffernan。干杯!
  • 这本来不是我的代码,只是落到我手里的东西,所以不能说作者的初衷。据我所知, Create 和 CreatePos 方法的意图只是初始化结构,所以我猜想调用它们构造函数只是为了让它们在代码中作为初始化方法在视觉上脱颖而出。但是由于我不确定,这基本上就是我在这里要问的,即这里的“构造函数”和“过程”之间是否存在任何功能差异,为什么我不应该只更改术语?另外,好奇,为什么 XE3 给出错误而 XE2 没有?

标签: delphi object constructor


【解决方案1】:

我有一段简单的代码,在 Delphi XE2 中编译,但在 XE3 中编译不出来,我不知道为什么。

您试图在已经实例化和初始化的实例的方法内调用构造函数。编译器不再允许这样做。更具体地说,这段代码:

procedure TCoordRect.Include(AX, AY: Real); 
begin 
  CreatePos(AX, AY, AX, AY) 
end; 

和这段代码是一样的:

procedure TCoordRect.Include(AX, AY: Real); 
begin 
  Self.CreatePos(AX, AY, AX, AY) 
end; 

你不能再在Self 变量上调用构造函数了。为什么? IIRC,它与编译器向支持移动开发的持续转变有关。

【讨论】:

  • +1 评论“这与编译器向支持移动开发的持续转变有关”。这是我得到的关于原因的最佳信息。当然,如果有更好的信息会很好,Delphi 文档也没有关于此错误消息的内容,所以这也很好。但是感谢您甚至给了这个! :)
  • 我认为 Remy 是在暗示正在开发的下一代编译器。 Emba 正在清理当前编译器中的一些奇怪之处,并尝试尽可能地使旧版编译器与下一代保持一致。
【解决方案2】:

对于这种传统的 Turbo Pascal 风格object,关键字constructor 确实没有任何意义。尽管object 构造函数确实有一些特殊处理,但这里绝对不需要。这里所拥有的只不过是带有一些方法的record

XE3 编译器已更改,因此它不再允许您在实例方法内调用 Self 上的构造函数。 classobject 都是这种情况。我没有看到任何文档说明为什么要进行此更改。毫无疑问,它会及时渗出。

您的直接解决方案是将constructor 替换为procedure。从长远来看,将其转换为record 而不是object 是有意义的。


我还建议您将方法名称更改为Initialize。一些图书馆设计师似乎选择在他们的记录中使用CreateFree 方法。这导致大量的代码是这样编写的:

ctx := TRttiContext.Create;
try
  ....
finally
  ctx.Free;
end;

事实上,所有这些代码都是虚假的,可以简单地删除! TRttiContext 变量会自动初始化。

这种设计也为喜欢使用FreeAndNil 的那群Delphi 程序员设置了一个巨大的Heffalump Trap。将记录传递给FreeAndNil 会引发一些有趣的烟花!

【讨论】:

  • 那么当您有多个构造函数(具有不同的名称)并且想要从另一个内部调用一个构造函数时,这将如何发挥作用。我确实希望这仍然被允许?应该是,毕竟都是构造函数,所以是类方法而不是实例方法……
  • @marjan 是的,这是允许的。
  • +1 表示“Heffalump 陷阱”。我现在热切期待以某种方式将其写入报告...... :)
  • 感谢您的好回答!您对这条评论留下了一些最后的小疑问:“虽然对象构造函数确实有一些特殊处理,但这里绝对不需要。”因为我在这里展示的是原始代码的简化版本,只是为了重现错误,所以我想知道这个“一些特殊处理”可能是什么,以防它仍然与原始代码有某种相关性我的。
  • 特殊处理是调用 System.pas 中的_ObjSetup,在对象中设置 VMT 指针。由于您的对象只不过是一个普通的旧记录,并且没有任何虚拟方法,因此不适用于此处。
猜你喜欢
  • 1970-01-01
  • 2013-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-12
相关资源
最近更新 更多