【问题标题】:How do I check that a descendent class overrides all virtual methods?如何检查后代类是否覆盖了所有虚拟方法?
【发布时间】:2018-03-06 09:08:52
【问题描述】:

上下文

在 DelphiAST 中有一个基类:TmwSimplePasPar,用于解析 Delphi 代码。
此外还有一个类:TPasSyntaxTreeBuilder,它应该覆盖其基类中的每个方法。

问题

有没有办法检查子类是否覆盖了其基类中的每个虚拟方法?
能加入断言就好了。

TPasSyntaxTreeBuilder.Create;
begin
  Assert(Self.OverridenMethods.Count = (BaseClass.VirtualMethodCount - TObject.VirtualMethodCount)); 
  ....

请注意,我说的是所有虚拟方法,而不仅仅是抽象方法(不实现抽象方法会发出警告)。

【问题讨论】:

  • 为什么不直接使用抽象方法呢?这就是他们的目的。如果基类中存在必须始终执行的行为,则让消费者调用基方法并让基方法执行必须由后代覆盖的抽象方法。
  • @J 我猜有第三方参与(DelphiAST?),所以 Johan 无法控制基类的来源。
  • @Nil DelphiAST 在 git 上...我很想亲自分支并修复它。这是一个糟糕的模式。
  • 询问或责怪20年前编写代码的原作者。
  • @J... 那么我同意,听起来抽象方法是实现 OP 目标的方法。

标签: delphi inheritance rtti virtual-functions


【解决方案1】:

查看类的 VMT 槽,并再次将它们与基类的 VMT 槽进行比较。

在Spring4D中有这个函数(在Spring.VirtualClass.pas):

function IsVirtualMethodOverride(baseClass, classType: TClass; method: Pointer): Boolean;

我不会在此处发布整个代码,因为它适用于某些内部 VMT 结构记录 - 请自行查看代码。

FWIW:我刚刚发现该例程中有一个小错误,我会尽快修复。

【讨论】:

  • 我自己没试过,但迭代 TRttiType.GetDeclaredMethods 并比较 Name 和 VirtualIndex 是一种有效的方法吗?
  • @UweRaabe 不,因为默认情况下您只能获得 public 及更高版本,并且通常虚拟方法受到保护
  • Stefan Glienke:虽然您认为所有虚拟方法都可能没有 RTTI 并没有错,但我认为这只是@UweRaabe 提出的问题的一部分答案。如果我没记错的话,仅比较 Name 和 VirtualIndex 是不够的。即使后代类覆盖了一个方法,这也是一样的,但是每个类的该 VirtualIndex 的 VMT 条目将指向不同的地址。在那里找到差异 - 就像在你的答案中一样 - 是关键。
  • 如果您查看TStream 的源代码,它会进行一些运行时检查以查看其虚拟方法是否已被覆盖。您可以应用类似的技术。
猜你喜欢
  • 1970-01-01
  • 2012-10-26
  • 1970-01-01
  • 2011-12-22
  • 1970-01-01
  • 2016-01-24
  • 2011-11-06
  • 1970-01-01
  • 2014-01-05
相关资源
最近更新 更多