【问题标题】:Why can I not use operator overloading for classes?为什么我不能对类使用运算符重载?
【发布时间】:2014-03-20 18:25:07
【问题描述】:

我在使用 TDateTime 中的类运算符时遇到问题。

type
  TDateTime = class(TObject)
  public
    class operator Add(a: TDateTime; b: TTimeSpan): TDateTime;
    class operator Subtract(a: TDateTime; b: TTimeSpan): TDateTime;
end;

implementation

class operator TDateTime.Add(a: TDateTime; b: TTimeSpan): TDateTime;
begin
  result := TDateTime.Create(a.Ticks + b.Ticks);
end;

class operator TDateTime.Subtract(a: TDateTime; b: TTimeSpan): TDateTime;
begin
  result := TDateTime.Create(a.Ticks - b.Ticks);
end;

错误发生在第 4 行

E2123 PROCEDURE、FUNCTION、PROPERTY 或 VAR 预期

我是为 Windows 编写的。但如果它仅适用于 .net 和 iOS,我该如何在 Windows 上做到这一点?

【问题讨论】:

    标签: delphi syntax operator-overloading


    【解决方案1】:

    可以在 Delphi for Windows 中使用运算符重载仅用于记录,而不用于类
    http://docwiki.embarcadero.com/RADStudio/Rio/en/Operator_Overloading_(Delphi)

    Some useful explanations

    附: TDateTime 是用户类型的错误名称。

    【讨论】:

      【解决方案2】:

      在 Delphi 的桌面版本(Windows、OSX)中,运算符重载仅适用于记录。对于移动版本的编译器,ARC 表示operator overloading is available for classes

      类的运算符重载

      使用 ARC 内存管理的一个非常有趣的副作用是编译器可以处理函数返回的临时对象的生命周期。一种特殊情况是运算符返回的临时对象。事实上,新的 Delphi 编译器的一个全新特性是能够为类定义运算符,其语法和模型与自 Delphi 2006 以来可用于记录的相同。

      如果我没记错的话,在现已停产的 .net 编译器中可以使用运算符重载。这再次成为可能,因为 .net 垃圾收集器可以清理任何临时对象。

      上面的文档摘录说明了为什么非 ARC 版本上的类无法实现运算符重载。如果没有一些自动生命周期管理,临时类就会泄露。另一方面,可以在堆栈上的自动存储中创建和销毁临时记录。

      也就是说,您的命名有点错误的类型看起来无论如何作为值类型可能会更好。因此,您的问题的解决方案是:

      1. 给你的类型起一个更好的名字,一个不会与基本类型冲突的名字。
      2. 将类型更改为record,即值类型。

      【讨论】:

      • 知道 C++ 如何在没有自动内存管理的情况下实现类运算符重载吗?
      【解决方案3】:

      附注:

      您可以在 Delphi .NET 编译器(从那时起已停止使用)中的类上使用它,因为 .NET 垃圾收集最终将删除操作符返回的新对象实例,并且最近在基于 ARC 的 Delphi ARM编译器(也基于引用计数释放内存)。

      回答你的问题:

      您不能在不支持 ARC 的本机 Delphi 编译器中的类上使用它(目前基于 Intel 的 Windows、OS X 和 iOS 模拟器的 x86 和 x64 编译器不支持 ARC),因为它会严重泄漏内存,因为运算符将返回没有人会释放的新对象实例。

      随着 ARC(目前是基于 ARM 的移动平台)的引入,您可以像那些编译器一样编译它。

      注意事项:

      • 小心重新定义现有的 Delphi 类型,如 TDateTime
      • 请注意,您只能在 ARC 编译器上使用以下代码,因此您正在编写高度依赖于平台的代码
      • 如果您想跨平台,请将其设为像 TTimeStamp record 这样的值类型

      在下面的代码中(仅适用于 ARC),将 class 替换为 record 使其跨平台。 .NET 框架的 TimeSpanDateTime(您的代码可能基于它们)是 struct 值类型,而不是 class 引用类型,这并非巧合。

      总而言之,在编写跨平台代码时,请注意值和引用类型,并在使用运算符重载时支持 record 值类型。

      type
        TTimeSpan = class
          Ticks: Longint;
        end;
      
        TDateTime = class
        public
          Ticks: Longint;
          class operator Add(a: TDateTime; b: TTimeSpan): TDateTime;
          class operator Subtract(a: TDateTime; b: TTimeSpan): TDateTime;
          constructor Create(aTicks: Longint);
        end;
      
      class operator TDateTime.Add(a: TDateTime; b: TTimeSpan): TDateTime;
      begin
        Result := TDateTime.Create(a.Ticks + b.Ticks);
      end;
      
      constructor TDateTime.Create(aTicks: Integer);
      begin
        Ticks := aTicks;
      end;
      
      class operator TDateTime.Subtract(a: TDateTime; b: TTimeSpan): TDateTime;
      begin
        Result := TDateTime.Create(a.Ticks - b.Ticks);
      end;
      

      【讨论】:

      • 这与问题中的代码相同。作为参考类型,它非常糟糕。我希望你不赞同这一点。
      • 您似乎仍然支持在此处使用引用类型。为什么?如果您必须包含代码,那么包含设计良好且可在所需平台上运行的代码肯定是有意义的。
      • 您的更新让您回答得更好。我必须说我确实想知道为什么您添加的答案与我的完全相同。你加了什么?我错过了什么吗?
      • 我可能是在您编辑答案时开始的。
      • 我对此表示怀疑。我的回答一直都是这么说的。编辑是轻微的润色。不过,选民似乎更喜欢你的版本! ;-)
      猜你喜欢
      • 2015-11-13
      • 2011-01-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-30
      • 1970-01-01
      • 2012-03-09
      相关资源
      最近更新 更多