1

我在 Delphi 2007 中使用第三方报告 VCL 包。我想为这个包的几个对象所具有的每个函数添加一些代码。但是,我想这样做,而不必在我的应用程序中重新编写大量代码。我现在拥有的是以下内容:

TBaseReport (Base object with all abstract functions)
     |
     --------------
     |            |
TViewReport   TPrintReport  (Descendents that do the actual implementation of the functions)

报告包在报告打印过程中调用了许多事件。每个事件都通过 TObject 参数传递一个 TViewReport(如果在屏幕上查看报告)或 TPrintReport(如果直接打印)的实例。例如:

Function TForm1.BeforePrint(Sender: TObject);
Begin
  With TBaseReport(Sender) Do // Type cast as TBaseReport so code works with either
  Begin                       //  TViewReport or TPrintReport.
    .... code here ...
  End;
End;

我想做的是创建一个新的 TBaseReport 后代(比如 TMyBaseReport),其中一些相同的函数被覆盖,以便在调用继承的代码之前先调用我自己的一些代码。当然,我的问题是我无法覆盖 TBaseReport,因为它的所有功能都是抽象的。所以我创建了两个对象来覆盖 TViewReport 和 TPrintReport。然后我尝试了以下方法:

Type
  TMyReportPrinter = Class(TReportPrinter)
  Public
    Procedure PrintText(X, Y: Integer; S: String); Override;
  End;

  TMyViewReport = Class(TViewReport)
  Public
    Procedure PrintText(X, Y: Integer; S: String); Override;
  End;

.
.
.

Function TForm1.BeforePrint(Sender: TObject);
Var
  Rpt: TBaseReport;
Begin
  If Sender Is TReportPrinter Then 
    Rpt := TMyReportPrinter(Sender) 
  Else
    Rpt := TMyViewReport(Sender);
  With Rpt Do 
  Begin       
    PrintText(1.5, 1.5, 'Foobar');
    .... same original code here ...
  End;
End;

Procedure TMyReportPrinter.PrintText(X, Y: Integer; S: String); 
Begin
  Inherited;
  LogMsg('PrintText called.');
End;

Procedure TMyViewReport.PrintText(X, Y: Integer; S: String); 
Begin
  Inherited;
  LogMsg('PrintText called.');
End;

但是 TMyReportPrinter 和 TMyViewReport 中的代码永远不会被调用。如果我对对象的创建没有任何控制权,是否可以覆盖对象?

4

1 回答 1

1

我假设 PrintText 未定义为虚拟方法,因此您不能覆盖它。

也许有一个事件(如 OnBeforePrintText)可用于添加额外的功能。

否则,您应该重新定义一些功能。

静态链接和动态链接的区别

当您有一个具有两个方法的类和一个覆盖其中一个方法的子类时:

type
  TBaseClass = class 
  public
    procedure MethodA; // Calls MethodB
    procedure MethodB;
  end;

  TSubClass = class (TBaseClass)
  public
    procedure MethodB;
  end;

现在你有了一个 TSubClass 对象并调用 MethodA。然后调用 TBaseClass 的 MethodB。这称为静态链接。TSubClass 的 MethodB 不被 TBaseClass 的 MethodA 调用。

但是如果您将 MethodB 声明为虚拟,并在 TSubClass 中使用覆盖:

type
  TBaseClass = class 
  public
    procedure MethodA; // Calls MethodB
    procedure MethodB; virtual;
  end;

  TSubClass = class (TBaseClass)
  public
    procedure MethodB; override;
  end;

现在 MethodB 是动态链接的。因此,当您在类 TSubClass 的对象上调用 MethodA 时,会调用 TSubClass 的 MethodB。

于 2013-04-18T13:45:49.700 回答