如何从第三方覆盖Delphi对象

时间:2013-04-18 13:18:08

标签: delphi inheritance delphi-2007

我正在使用第三方报告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中的代码。如果我无法控制对象的创建,那么无论如何都要覆盖一个对象吗?

1 个答案:

答案 0 :(得分: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。这称为静态链接。 TSaseClass的MethodB不被方法A的TBaseClass调用。

但是如果将MethodB声明为virtual,并在TSubClass中使用override:

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。