views:

1243

answers:

2

I'm trying to create a child class of TForm with

  1. a special constructor for certain cases, and
  2. a default constructor that will maintain compatibility with current code.

This is the code I have now:

interface
  TfrmEndoscopistSearch = class(TForm)
  public
    /// original constructor kept for compatibility
    constructor Create(AOwner : TComponent); overload; override;
    /// additional constructor allows for a caller-defined base data set
    constructor Create(AOwner : TComponent; ADataSet : TDataSet; ACaption : string = ''); overload;
  end;

It seems to work, but I always get the compiler warning:

[Warning] test.pas(44): Method 'Create' hides virtual method of base type 'TCustomForm'
  • Adding "overload;" after the second constructor won't compile. "[Error] test.pas(44): Declaration of 'Create' differs from previous declaration".
  • making the second constructor a class function compiles without any errors or warnings, but dies with an access violation at runtime (all member vars are nil).
+5  A: 

Try adding reintroduce before the second overload, like this:

  TfrmEndoscopistSearch = class(TForm)
  public
    /// original constructor kept for compatibility
    constructor Create(AOwner : TComponent); overload; override;
    /// additional constructor allows for a caller-defined base data set
    constructor Create(AOwner : TComponent; ADataSet : TDataSet; ACaption : string = ''); reintroduce; overload;
  end;

This compiles in Turbo Delphi. I needed the public to make it compile because overloading of published methods is restricted.

Ulrich Gerhardt
After the second one.
Smasher
I just tried - it is *before*. :-)
Ulrich Gerhardt
ah, I thought you mean after the first or the second declaration :) always confused about the order too though.
Smasher
Sorry for having been unclear.
Ulrich Gerhardt
bango! The "reintroduce" keyword is exactly what is needed. The original constructor is also needed because it sets the data set to the proper default value.
David Dombrowsky
+7  A: 

There's a really easy way to avoid this. Give your new constructor a different name. Unlike some other popular languages, Delphi has named constructors; you don't have to call them Create. You could call your new one CreateWithDataset and not interfere with the virtual Create constructor at all.

TfrmEndoscopistSearch = class(TForm)
  /// original constructor kept for compatibility
  constructor Create(AOwner: TComponent); override;
  /// additional constructor allows for a caller-defined base data set
  constructor CreateWithDataset(AOwner: TComponent; ADataSet: TDataSet; ACaption: string = '');
end;

In fact, unless you're instantiating this class polymorphically, you don't even need the original constructor. You could declare your new one like this:

TfrmEndoscopistSearch = class(TForm)
  /// additional constructor allows for a caller-defined base data set
  constructor Create(AOwner: TComponent; ADataSet: TDataSet; ACaption: string = ''); reintroduce;
end;

Attempting to call the one-argument constructor directly on TfrmEndoscopistSearch would yield a compilation error.


(Creating it polymorphically would generally involve using Application.CreateForm:

Application.CreateForm(TfrmEndoscopistSearch, frmEndoscopistSearch);

That always calls the one-argument virtual constructor introduced in TComponent. Unless it's your main form, you don't need to do that. I've written about my feelings on Application.CreateForm before.)

Rob Kennedy
This is probably the most appropriate solution, but it isn't the answer to the question. Part of the exercise is to fix the problem and not have to change any of the other 10-or-so files that already use one or the other form of create(). I'm merging this form together from two different projects and didn't want to fork it.
David Dombrowsky