I want to have a MainForm that is derived from a BaseForm that has a custom constructor. Since this is the Mainform, it is created by a call to Application.CreateForm(TMyMainForm, MyMainForm) in the *.dpr file. However, my custom constructor is not called during form creation.
Obviously, it works fine, if I call MyMainForm := TMyMainForm.Create(AOwner). Can I not use a form with custom constructor as the main form ?
TBaseForm = class(TForm)
constructor Create(AOwner:TComponent; AName:string);reintroduce;
end;
TMyMainForm = class(TBaseForm)
constructor Create(AOwner:TComponent);reintroduce;
end;
constructor TBaseForm.Create(AOwner:TComponent);
begin;
inherited Create(AOwner);
end;
constructor TMyMainForm.Create(AOwner:TComponent);
begin;
inherited Create(AOwner, 'Custom Constructor Parameter');
end;
Application.CreateForm()
cannot call a reintroduce
'd constructor. When creating a new object, it calls the TComponent.Create()
constructor and expects polymorphism to call any derived constructors. By reintroduce
'ing your custom constructor, you are not part of the polymorphic call chain. reintroduce
exposes a completely new method that simply has the same name as an inherited method but is not related to it.
To do what you are attempting, don't use reintroduce
for your constructors. Create a separate constructor in your Base form, and then have your MainForm override
the standard constructor and call your custom Base constructor, eg:
TBaseForm = class(TForm)
constructor CreateWithName(AOwner: TComponent; AName: string); // <-- no reintroduce needed since it is a new name
end;
TMyMainForm = class(TBaseForm)
constructor Create(AOwner: TComponent); override; // <-- not reintroduce
end;
constructor TBaseForm.CreateWithName(AOwner: TComponent; AName: string);
begin;
inherited Create(AOwner);
// use AName as needed...
end;
constructor TMyMainForm.Create(AOwner: TComponent);
begin;
inherited CreateWithName(AOwner, 'Custom Constructor Parameter');
end;
In order for a form to become the VCL main form, it must be created via a call to Application.CreateForm
. That in turn calls the virtual constructor declared in TComponent
. So, there's no way to get a different constructor to be called for the VCL main form.
One option is that presented by Remy. To override the constructor declared in TComponent
, and call a different constructor passing extra parameters. That can be a constructor in the same class, or an inherited constructor from a base class.
Another option here would be to use abstract class methods on a base class. For instance,
type
TMainFormBase = class(TForm)
protected
class function ProjectName: string; virtual; abstract;
class function RegKeyPath: string; virtual; abstract;
end;
In your derived classes you would override these abstract methods. Instead of setting properties in the constructor, code in the base form class could just call these methods. Of course, if you needed to do work in the constructor, you could perfectly well call these methods from the constructor.
Personally I have a prejudice against adding new constructors to classes that already have virtual constructors. The virtual constructor paradigm leads you towards using that single virtual constructor, and nothing else. If you start adding different constructors further down the hierarchy then it's just all too easy to end up with trouble caused by the wrong constructor being called when instantiating virtually.