Frage

I am using a third party reporting VCL package in Delphi 2007. I want to add some code to each of the functions that a couple of objects of this package have. But, I want to do it without having to re-write a lot of code in my application. What I have now is the following:

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

The reporting package calls a number of events during the report print process. Each event is passed a TObject parameter with an instance of either a TViewReport (if viewing the report on the screen) or a TPrintReport (if printing directly). For example:

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;

What I would like to do is create a new descendent of TBaseReport (say TMyBaseReport) with some of the same functions overrided to call some of my own code first before calling the inherited code. The problem I have, of course, is that I cannot override TBaseReport because all of it's functions are abstract. So I created two objects to override TViewReport and TPrintReport. Then I tried something like the following:

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;

But the code in TMyReportPrinter and TMyViewReport is never called. Is there anyway to override an object if I don't have any control over the creation of the object to begin with?

War es hilfreich?

Lösung

I assume PrintText is not defined as a virtual method, so you can't override it.

Maybe there is an event (like OnBeforePrintText) that can be used to add extra functionality.

Else you should redefine some of the functionality.

The difference between static and dynamic linking

When you have a class with two methods and a subclass that overrides one of them:

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

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

Now you have an object of TSubClass and call MethodA. Then then MethodB of TBaseClass is called. This is called static linking. MethodB of TSubClass is not called by MethodA of TBaseClass.

But if you declare MethodB as virtual, and use override in TSubClass:

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

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

Now MethodB is dynamically linked. So when you call MethodA on an object of class TSubClass, MethodB of TSubClass is called.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top