我希望有一个从具有自定义构造函数的BaseForm派生的MainForm。由于这是Mainform,因此它是通过调用* .dpr文件中的 Application.CreateForm(TMyMainForm,MyMainForm)创建的。但是,在表单创建期间不会调用我的自定义构造函数。
显然,如果我调用 MyMainForm:= TMyMainForm.Create(AOwner),它的工作正常。我可以不使用自定义构造函数的表单作为主要表单吗?
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;
答案 0 :(得分:8)
Application.CreateForm()
无法调用reintroduce
' d构造函数。在创建新对象时,它会调用TComponent.Create()
构造函数并期望多态来调用任何派生的构造函数。通过reintroduce
自定义构造函数,您不是多态调用链的一部分。 reintroduce
公开了一个全新的方法,该方法与继承的方法具有相同的名称,但与之无关。
要执行您尝试的操作,请不要将reintroduce
用于构造函数。在Base表单中创建一个单独的构造函数,然后让MainForm override
成为标准构造函数并调用自定义Base构造函数,例如:
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;
答案 1 :(得分:2)
为了使表单成为VCL主表单,必须通过调用Application.CreateForm
来创建表单。这反过来调用TComponent
中声明的虚构造函数。因此,没有办法为VCL主窗体调用不同的构造函数。
雷米提出的一个选择。要覆盖TComponent
中声明的构造函数,并调用另一个传递额外参数的构造函数。它可以是同一个类中的构造函数,也可以是基类中的继承构造函数。
这里的另一个选择是在基类上使用抽象类方法。例如,
type
TMainFormBase = class(TForm)
protected
class function ProjectName: string; virtual; abstract;
class function RegKeyPath: string; virtual; abstract;
end;
在派生类中,您将覆盖这些抽象方法。基本表单类中的代码可以只调用这些方法,而不是在构造函数中设置属性。当然,如果你需要在构造函数中工作,你可以很好地从构造函数中调用这些方法。
我个人对于在已经拥有虚拟构造函数的类中添加新构造函数存在偏见。虚构造函数范例引导您使用该单个虚拟构造函数,而不是其他任何东西。如果你开始在层次结构中进一步添加不同的构造函数,那么在虚拟实例化时,由于错误的构造函数被调用而导致的麻烦就太容易了。