30

overridereintroduce指令有什么区别?我什么时候不应该inherited在被覆盖的方法中使用关键字?

4

4 回答 4

48

顺便说一句,对 Jim 的回答的引用非常好,它只描述了何时何地使用这些指令。答案的另一部分是为什么仍然需要它们?没有它们,许多语言相处得很好,对吧?在设计 Delphi 对象 Pascal 语言的各个方面时,OOP(面向对象编程)已经成为主流好几年了。在此期间,观察到使用许多采用这些概念的语言(Turbo Pascal、C++ 等)来开发应用程序框架会遇到我所谓的“版本 2”问题。

假设您使用语言 X 开发了一个很棒的框架并将其作为版本 1 发布。您的用户对它所能做的一切都赞不绝口,并且它被大量使用。大获全胜,您决定发布更棒的第 2 版。您特别确保它完全向后兼容。突然,您的用户开始报告奇怪的行为。他们自己的虚拟方法在奇怪的时间被调用。许多人报告说他们的旧代码无法与新版本一起编译。奇怪的。所有相同的对象、方法和功能仍然保留。您所做的只是向一些基类、一些新的对象类型和一些新的可选功能添加一些虚拟方法。发生了什么?

override 和 reintroduce 指令通过要求为了实际覆盖虚拟方法必须使用 override 指令代替 virtual 指令来消除此问题。如果您碰巧引入了您自己的与您祖先的虚拟方法之一同名的虚拟方法,编译器现在会警告您,但仍会做正确的事情。在这种情况下,使用 reintroduce 不仅可以抑制该警告,还可以在您打算执行此操作的源中记录。

如果没有 override 和 reintroduce 指令,您将无法在不担心破坏所有用户的情况下不断发展您的框架。如果您的用户每次发布新版本时都必须进行大量修改,那么他们将不愿意采用新版本。最后,使用“覆盖”还允许框架设计者在不破坏用户代码的情况下更改祖先中的虚拟类型。例如,在 Delphi 中,许多方法都被标记为“动态”,这是一种基于表的运行时方法查找形式的多态性。它的执行速度不如常规 virtual 快,因此它通常用于很少被覆盖的方法和/或对用户操作的响应,而这些额外开销从未被注意到。假设在框架的 V1 中,一个方法被标记为“动态” 但在实践中,它最终被覆盖并调用了超出您预期的次数。在 V2 中,您可以将其更改为“虚拟”,而不必担心用户的代码被破坏。

Delphi 的 Object Pascal 语言并不是唯一能识别这个问题的语言。出于完全相同的原因,C# 需要使用“覆盖”指令。C++ 标准委员会终于认识到了这个问题,并正在修改语言以支持它……有点。在 C++ 中,如果一个方法的名称和参数列表与祖先的虚拟匹配,那么它就是一个覆盖(即使你没有在后代上说“虚拟”!)。对于即将推出的新 C++ 标准,如果您指定“虚拟”并且签名不匹配,那么它是当前类中引入的新虚拟方法。如果与祖先有签名匹配并且作者打算覆盖,那么“新”

于 2009-04-12T17:53:03.157 回答
11

override指令用于覆盖继承类中的虚拟方法。

reintroduce指令用于声明与超类中同名但参数不同的方法。

于 2009-04-12T15:46:25.347 回答
6

什么时候不应该在被覆盖的方法中使用inherited关键字?

基本上,答案是当您不希望执行继承的方法时。请注意,不允许运行继承的方法可能会以不希望的方式破坏继承对象的功能,因此请确保您没有引入任何意外的副作用。

例如,假设您希望完全覆盖一个名为 ApplyDiscount 的继承函数,但有人将折扣百分比硬编码到祖先类中。如果您调用继承的 ApplyDiscount,它将覆盖您的代码或计算您将覆盖的值;在这种情况下,您不能调用继承并自己应用折扣。

(这是一个人为的例子,所以如果有人能想到更好的例子,请添加它。)

于 2009-04-12T18:22:41.617 回答
1

在许多情况下,您不想在被覆盖的方法中调用继承。

在我使用的某些库中,基本方法会引发错误(ENotImplimented 或类似的)。显然,在这种情况下,您不想调用inherited,否则您的代码也会抛出错误。

我的一些类有一个在大多数情况下都有效的默认实现。该方法只是覆盖替换默认值,不需要调用默认值。

例如,我的基本财务对象的 GST 函数(= 销售税)返回 ExGst 金额的 12.5%,而 IncGst 返回 ExGst + GST。

在我的收入补偿对象上,GST 始终返回 0,因此无需调用继承的函数。

于 2009-04-12T21:54:55.790 回答