Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi/pascal: overloading a constructor with a different prototype

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).
like image 229
David Dombrowsky Avatar asked Nov 18 '09 20:11

David Dombrowsky


3 Answers

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.)

like image 65
Rob Kennedy Avatar answered Nov 01 '22 12:11

Rob Kennedy


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.

like image 30
Uli Gerhardt Avatar answered Nov 01 '22 13:11

Uli Gerhardt


constructor Create(AOwner:Tcomponent;str:string);overload;
... 
constructor TfrmEndoscopistSearch.Create(AOwner: Tcomponent; str: string);
    begin
    inherited Create(AOwner);
    showmessage(str);
    end;

This should do the trick

like image 7
Radacina Avatar answered Nov 01 '22 14:11

Radacina