delphi 类帮助器中断虚拟方法的重写

qyzbxkaa  于 2023-10-18  发布在  其他
关注(0)|答案(1)|浏览(128)

考虑以下 Delphi 控制台应用程序:

program Project1;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils;

type
  TC1 = class
    procedure m; virtual;
  end;

  TC2 = class(TC1)
    procedure m; override;
  end;

  type THelper = class helper for TC1
    procedure m;
  end;

procedure TC1.m; begin WriteLn('C1') end;
procedure TC2.m; begin WriteLn('C2') end;
procedure THelper.m; begin inherited m end;

procedure p(c : TC1);
begin
  C.m
end;

begin
  var C := TC2.Create;
  p(c);
  ReadLn
end.

我希望THelper的存在不会改变继承并打印“C2”,但程序会打印“C1”,因此不会调用重写的C2.m
当注解掉THelper(和THelper.m)时,程序按预期打印“C2”。

ghg1uchk

ghg1uchk1#

在本例中,THelper.m()优先于TC1.m()。这是预期和记录的行为:
Class and Record Helpers (Delphi)
下面的代码演示了类助手的声明(记录助手的行为方式相同):

type
  TMyClass = class
    procedure MyProc;
    function  MyFunc: Integer;
  end;

...

procedure TMyClass.MyProc;
var X: Integer;
begin
  X := MyFunc;
end;

function TMyClass.MyFunc: Integer;
begin
  ...
end;

...

type
  TMyClassHelper = class helper for TMyClass
    procedure HelloWorld;
    function MyFunc: Integer;
  end;

...

procedure TMyClassHelper.HelloWorld;
begin
  Writeln(Self.ClassName); // Self refers to TMyClass type, not TMyClassHelper
end;

function TMyClassHelper.MyFunc: Integer;
begin
  ...
end;

...

var
  X: TMyClass;
begin
  X := TMyClass.Create;
  X.MyProc;    // Calls TMyClass.MyProc
  X.HelloWorld; // Calls TMyClassHelper.HelloWorld
  X.MyFunc;    // Calls TMyClassHelper.MyFunc

提示:记住,类助手函数MyFunc被调用,因为类助手优先于实际的类类型
最后强调的部分是为什么p()调用THelper.m()而不是TC1.m()
由于THelper.m()正在调用inherited m(),这是对TC1.m()的直接调用,因此不会发生虚拟方法分派,这就是为什么TC2.m()根本不会被调用,即使p()c参数指向TC2对象。
如果让THelper.m()调用Self.m()而不是inherited m(),这将允许编译器调用TC1.m()上的虚方法分派,从而调用TC2.m(),因为THelper内部的Self指针引用TC1,而不是THelper

相关问题