【问题标题】:Record methods and const parameters in Delphi在 Delphi 中记录方法和 const 参数
【发布时间】:2011-09-14 09:11:59
【问题描述】:

看起来 Delphi 编译器在以下情况下不支持 const 记录参数 涉及“记录方法”。

之前没有尝试滥用 const 约定,我有点惊讶 找到编译器接受的代码:

type
    TTest = record
       Field : String;
       procedure Update;
    end;

procedure TTest.Update;
begin
    Field := Field + '+1';
end;

procedure DoStuff(const t : TTest);
begin
    ShowMessage(t.Field);
    t.Update;
    ShowMessage(t.Field);
end;

如果你尝试做一个 t.Field:='doh'; in DoStuff f.i.,编译器会正确地抱怨,但你可以调用修改“const”记录的方法,甚至没有提示或警告。因此,这与引用类型(例如类或动态数组)的行为不同,后者允许直接字段写入(因为 const 仅限制对参数本身的更改)。

附录:这也允许以这种方式修改声明的编译时常量,如:

const
   cTest : TTest = (Field : '1');
...
cTest.Update;              // will show '1' then '1'+'1'
ShowMessage(cTest.Field);  // will show '1' (because optimized at compile-time)

这是一种公认​​的/记录在案的行为吗?还是只是编译器的缺点?

【问题讨论】:

  • 我更新了附录以直接调用 Update 方法,因为在我看来这是这里的根本问题。您需要记录的方法来改变 const 记录。
  • 恕我直言,这里真正的错误是UpdateValue types should be used as immutable。 (链接是 C# 示例,抱歉,但想法是一样的。)另见 this SO answer
  • @David,您对附录的编辑使该示例无效。直接调用Update 会修改字段值,但我们看不到该更改的结果,因为编译器显然在随后的ShowMessage 语句中优化了对它的直接访问。
  • @Rob 我的编辑是在ShowMessage 之前进行的,并进行了优化。在我进行编辑时,我认为这是合理的。
  • DoStuff 在编辑前故意在示例中,以表明在实践中它可能发生在不明显的情况下。

标签: delphi methods record


【解决方案1】:

const 在 Delphi 中从不限制方法调用,无论是记录还是类实例。所以我觉得方法调用的处理方式并没有什么不一致的地方。

如果无法在作为const 参数传递的记录上调用方法,那么这几乎会使带有方法的记录变得无用。例如,这意味着无法调用属性 getter。为了对以const 传递的此类记录施加限制,需要有一个与 C++ 的 const 成员函数等效的概念。这将使编译器知道某些方法是非变异的。

【讨论】:

  • 编译器可以自己判断哪些方法正在变异,哪些没有,并相应地调整隐藏的调用约定。事实上,'const' 说明符被渲染为无用。
  • 这会导致非常糟糕的事情发生,例如修改编译时声明的常量(我已经用一个示例更新了问题)
  • 似乎 OP 希望所有被调用的过程都具有“nosideeffects;”装饰或其他东西,然后让编译器强制执行?
  • @Warren 这就是 C++ const 成员函数的作用。
  • @Eric:我完全同意大卫的观点。与 C++ 不同,Delphi 中没有 const 方法,因此允许任何方法调用。只允许直接修改记录。您可以向 Embarcadero 建议 const 方法,但是 ATM,它们不存在,也就是说,IMO,很好。我不希望编译器分析你调用的每一个方法来查看它是否修改了 const 参数的状态。
【解决方案2】:

David 很好地分析了限制。如果编译器要检查这些细节,它确实会受到一些惩罚。此外,我认为编译器的行为没有任何问题。获取记录的方法不能直接改变它的数据,只有在使用它包含的方法时才可以。在这种情况下,记录就像一个对象:您可以以与 const 相同的方式使用对象,但仍然遇到您描述的相同问题,即。对象的方法可用于更改其数据。

对象的好处是,可以将此类方法声明为私有的,这使您能够保护其数据。你甚至可以创建一个继承的类来做到这一点,即隐藏所有改变其数据的可能性。也许您想尝试这种方法?

【讨论】:

  • 是的,但是对象是引用类型,记录是值类型。看起来属性为“const”提供了类似的绕过,我猜结论是“const”对记录也没有意义,除了调用优化。
  • 对。但对记录使用“const”并非毫无意义,尤其是在它们不包含任何方法的情况下。
  • 请注意,它也会影响编译时常量记录,有点像恢复“可写常量”编译器选项。
  • 尝试使用旧式对象类型。我期望与记录相同的行为。正如我在另一条评论中所说,这很好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多