[教程]怎么在父类中判断一个类的虚拟成员函数当前是否被子类继承过

【应用场景】

父类要根据子类是否实现了对应的接口来判断是否执行指定的代码。注意一点,Delphi 是支持纯虚函数成员的类创建实例,所以如果父类不需要特殊处理,可以直接定义为纯虚函数。但调用的时候,我们可能要判定下它是否被重载,以决定是否调用。

【实现思路】

问了 AI 几次,给出的方案都不是很满意,存在硬编码和其它限制,所以自己手动写了下。

1、通过递归 ClassType 找到父类的 ClassType 定义。

2、找到父类对应函数的代码地址。

3、比较当前类对应方法的代码地址是否与父类对应函数的代码地址一致。

【参考代码】

type
  TfmBase=class(TFrame)
  ...
  protected
    procedure DoQuickQuery;virtual;abstract;
  public
    procedure AfterConstruction;override;
  end;

procedure TfmBase.AfterConstruction;
type
  TMethodType=procedure (Sender:TObject) of object;
var
  Addr,ABase:TMethodType;
  AChildMethod:TMethod absolute Addr;
  ABaseMethod:TMethod absolute ABase;
  AClass:TClass;
begin
  AClass:=ClassType;
  while AClass<>TfmBase do
    AClass:=AClass.ClassParent;
  ABase:=TfmBase(@AClass).DoQuickQuery;
  Addr:=DoQuickQuery;
  if ABase.Code<>Addr.Code then
     RegisterShortcut('快速查询',Shortcut(VK_RETURN,[ssCtrl]),DoQuickQuery);
end;

上面的代码中,RegisterShortcut 函数只有检测到子类实现了 DoQuickQuery 时,才会在用户按下 Ctrl+回车 时,自动调用 DoQuickQuery 来执行对应的查询。比如:

type
  TfmOrderManager=class(TfmBase)
  protected
    procedure DoQuickQuery;override;
  end;
...
procedure TfmOrderManager.DoQuickQuery;
begin
  ShowMessage('Hello,world');
end;

这样就不需要子类重复去注册一些公共行为,只需要实现即可。

滚动至顶部