【问题标题】:Why isn't operator overloading available for classes in Delphi?为什么 Delphi 中的类不能使用运算符重载?
【发布时间】:2011-01-06 14:56:55
【问题描述】:

我一直想知道这一点,但为什么 Delphi 中的类不能使用运算符重载?

我记得在跑步时读过一次答案,它说它会与某些东西发生冲突,但我记不起来了。据我所知,只有隐式运算符可能会导致一些问题,因为类存储在堆上,分配实际上是堆地址的副本(基本上是复制指针)。

【问题讨论】:

  • 它可以在 Delphi.NET 中工作,因为 .NET 会进行垃圾收集。这可以在本机 Delphi 中通过两种方式解决: 1. 如果接口上允许运算符,并且实现这些运算符的类将从 TInterfacedObject 继承。 2. 如果托管类被添加到 Delphi 语言中。现在,Mason 是对的:你会到处出现内存泄漏。另请参阅此链接上引用的我的演讲:wiert.wordpress.com/2009/10/19/…
  • 是的,我明白为什么这可能被视为一个问题,而这正是我在那篇文章中读到的内容,现在我记得了。但是,正如我在对 Mason 回答的评论中所说的那样,我认为这实际上并不是一个限制,因为我认为如果您只实施一点垃圾收集(不会有任何副作用),您就可以做到这一点。
  • 如果接口有运算符,那么就会出现很多问题,例如无法取消某些运算符。例如,想象在接口中有一个隐式运算符,然后有一个确实需要该接口但绝对不需要隐式运算符的对象。当你尝试一项任务时,所有的地狱都可能会崩溃,而且很难找到你的问题。问题是,运算符永远不应该被继承,如果你想使用“继承”的版本,你应该再次重载它,然后进行类型转换。但这意味着类也必须拥有它。
  • 托管类不就是记录吗?当然,它们没有继承和真正定义 OOP 的所有其他特性,但它们可以。
  • 是的,您可以将运算符重载实现为接口,但这会导致其自身的问题。一旦你获取一个 TInterfacedObject 并将其接口引用计数设置为 1,将其视为普通对象不再安全,因为一旦对它的最后一个接口引用消失,它就会消失。

标签: delphi class operator-overloading


【解决方案1】:

关闭。这是因为对象是引用类型,内存是手动管理的。所以如果你说myResult := myObject1 + myObject2 + myObject3;,你必须在那里的某个地方创建一个中间对象,并且没有释放它的代码,所以你会出现内存泄漏。

【讨论】:

  • 编译器可以添加代码来管理字符串,为什么不能处理隐藏对象呢?我不认为这是原因。
  • @mj2008:一方面,字符串没有也不能有自定义构造函数。如果没有使用适当的构造函数实例化这种情况下的中间对象,那么它们很可能是无效的,并且编译器可能并不总是/永远能够确定适当的参数。我怀疑为支持运算符重载而必须对类施加的限制会超过好处。而且由于您现在可以拥有“带有方法的记录”,因此您可以根据需要结合使用运算符重载。
  • 我明白为什么乍一看它不起作用。但是,在这种情况下,编译器不能自动销毁除最后一个之外的中间对象,然后将赋值视为正常吗?例如,首先创建 myIntermediaryObject1 作为 (myObject1 + myObject2) 的结果,然后添加它与 myObject3 创建 myIntermediaryObject2,自动销毁 myIntermediaryObject1 并照常进行分配?毕竟,如果有必要,程序员有责任去处理 myResult 的分配,而编译器可以处理其余的临时对象。
  • “带有方法的记录”的问题,顺便说一句,记录没有像继承这样的 OOP 特性(这基本上也取消了多态性、虚拟方法和所有其他让我们使用的东西代替类,即使没有必要)。
  • 编译器无法销毁中间对象的原因是它根本无法知道是否存在任何“中间”对象。运算符可能会从以前的长计算中返回某个缓存对象的实例,或者它可能返回一个操作数对象,或者它可能返回需要在当前表达式之外继续存在的东西,例如表示 AST 的对象稍后将在程序中进行评估。编译器不知道对象从何而来,也不知道你以后会用它做什么。
【解决方案2】:

您可以对类进行运算符重载,但仅限于类使用 ARC 的 NextGen 编译器。
见:http://blog.marcocantu.com/blog/class_operators_delphi.html

这是在 XE5 中引入的,请参阅:List of Delphi language features and version in which they were introduced/deprecated

【讨论】:

    【解决方案3】:

    Mason Wheeler 说这是不可能的,因为中间对象管理。

    但根据 Embarcadero 文档,Delphi 2009 中的类运算符尽可能使用。

    RAD Studio 2009 - Operator Overloading New Delphi language features since Delphi 7

    【讨论】:

    • 运算符重载用于记录。记录是值类型,而类是引用类型。您链接中的文档是错误的(尽管他们声明此功能用于记录,但由于在示例中使用类而失败)。见XE3 Operator Overloading
    • 只允许在记录中,不允许在类中。但是现在有了 XE,记录可以有方法和属性。所以...
    • @All 文档就是这样,因为 .net 编译器支持对类进行操作重载。可能是因为 GC。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-13
    • 2013-07-30
    • 1970-01-01
    • 2023-03-25
    • 2018-03-16
    • 1970-01-01
    相关资源
    最近更新 更多