[fpc-pascal] class of - instance created is wrong

Graeme Geldenhuys graemeg.lists at gmail.com
Thu Mar 15 10:07:20 CET 2012


Hi,

I've used the Class Of language feature a lot in the past. eg: tiOPF
uses it a lot, I use it to generate various reports in our company
projects etc.

So I tried to implement a "lazy mans" factory method in my project, so
it can generate a class instance based on what the developer chooses.

I have the Class Of defined as follows...


  TfpgCanvasBase = class(TObject)
     ...
  end;

  TfpgCanvasBaseClass = class of TfpgCanvasBase;


I have a few Canvas class hierarchies. Here are two of them, which I'm
trying to use in this example:


  TfpgCanvas
   |
   +-- TfpgX11Canvas
        |
        +-- TfpgCanvasBase


  TAgg2D
   |
   +-- TfpgCanvasBase



I then have a global variable which will point to the actual class
type to instantiate.

  DefaultCanvasClass: TfpgCanvasBaseClass = nil;


Then somewhere early on in your project you can define which Canvas
class to use by simply doing the following...

   DefaultCanvasClass := TfpgCanvas;
or
   DefaultCanvasClass := TAgg2D;



Here is the simple factory method that the Window class uses to
instantiate a new Canvas object.
Excuse the Writeln() statements and comment - they are for debugging purposes.

function TfpgWindow.CreateCanvas: TfpgCanvasBase;
begin
  writeln('>> TfpgWindow.CreateCanvas');
  writeln('     DefaultCanvasClass = ' + DefaultCanvasClass.ClassName);
//  result := TAgg2D.Create(self);
//  result := TfpgCanvas.Create(self);
  Result := DefaultCanvasClass.Create(self);
  writeln('<< TfpgWindow.CreateCanvas');
end;


I then have Writeln() statements in each Canvas constructor outputting
the name of that class. So when a TfpgCanvas instance is created, the
output should  be similar to the class hierarchy listed above.


Now the problem...


Using the DefaultCanvasClass to create an instance, it seems to leave
out the latest class in the hierarchy. So if DefaultCanvasClass =
TfpgCanvas, I see console output as follows;

  creating... TfpgX11Canvas
  creating... TfpgCanvasBase

NOTE the missing TfpgCanvas. Needless to say my program crashes instantly.

The same happens when DefaultCanvasClass = TAgg2D. The console output is then.

  creating... TfpgCanvasBase

Again, the actual TAgg2D class constructor is by-passed somehow?? Yet
the writeln() statement inside the CreateCanvas() method, which asks
for the ClassName of DefaultCanvasClass, DOES output the correct class
name. TfpgCanvas or TAgg2D.


Now if I change CreateCanvas() to create a instance of a Canvas class
directly - without the usage of DefaultCanvasClass... One of the two
commented out lines of code, then everything works fine. But
obviously, I don't want to hard-code which canvas class to use.


Can anybody see what I am doing wrong? I've tested with FPC 2.6.0,
2.6.1 and 2.7.1 under 64-bit Linux. All compilers give the same
results. Like I've said, I have used the Factory Method pattern many
times (though a bit more advanced than what I did here - normally
using a mapping class), and it always works well.

BTW:
I took this global variable idea from the fptimer implementation,
which is part of FPC. I assume the fptimer implementation works
correctly.



-- 
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net



More information about the fpc-pascal mailing list