ave*_*ore 1 delphi constructor
我已经以基本形式重新引入了表单构造函数,但是如果我以子格形式覆盖原始构造函数,则重新引入的构造函数将不再可见.
type
TfrmA = class(TForm)
private
FWndParent: HWnd;
public
constructor Create(AOwner: TComponent; const AWndParent: Hwnd); reintroduce; overload; virtual;
end;
constructor TfrmA.Create(AOwner: TComponent; const AWndParent: Hwnd);
begin
FWndParent := AWndParent;
inherited Create(AOwner);
end;
type
TfrmB = class(TfrmA)
private
public
end;
type
TfrmC = class(TfrmB)
private
public
constructor Create(AOwner: TComponent); override;
end;
constructor TfrmC.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
end;
Run Code Online (Sandbox Code Playgroud)
创建时:
frmA := TfrmA.Create(nil, 0);
frmB := TfrmB.Create(nil, 0);
frmC := TfrmC.Create(nil, 0); // Compiler error
Run Code Online (Sandbox Code Playgroud)
我的解决方法是覆盖重新引入的构造函数或声明原始构造函数重载,但我想了解这种行为的原因.
type
TfrmA = class(TForm)
private
FWndParent: HWnd;
public
constructor Create(AOwner: TComponent); overload; override;
constructor Create(AOwner: TComponent; const AWndParent: Hwnd); reintroduce; overload; virtual;
end;
type
TfrmC = class(TfrmB)
private
public
constructor Create(AOwner: TComponent; const AWndParent: Hwnd); override;
end;
Run Code Online (Sandbox Code Playgroud)
在您的初始代码中,您的Create构造函数隐藏了原始Create.这就是为什么编译器抱怨TfrmC重写一个它不能再从那里看到的构造函数的原因.
您通常会收到有关此内容的编译器消息,但"重新引入"会抑制此情况.每当你需要"重新引入"来抑制编译器消息时,警报响应就会消失,因为这表明你正在破坏多态性.并不意味着你不应该使用它,但你应该意识到其含义.
在这些情况下,如果我想保留覆盖原始构造函数的能力,我倾向于添加一个不同的构造函数,即
constructor CreateWithParent(AOwner: TComponent; const AWndParent: HWnd); virtual;
Run Code Online (Sandbox Code Playgroud)
并在其实现中调用原始构造函数.它确实意味着我需要调用一个不同的构造函数,但是你已经需要传递另一个参数,这似乎不是一个糟糕的权衡.
编辑:正如我在评论中提到的,编译器抱怨tfrmC.Create(nil,0); 参数太多了.似乎tfrmC.Create(AOwner)隐藏了tfrmA.Create(AOwner,AWndParent); 在回家的路上考虑它(交通堵塞似乎总是有优势),有一个解释.
1)tfrmA.Create上的重载除了允许引入具有相同名称的其他构造函数之外没有任何直接目的.2)TfrmC构造函数有效地隐藏了TfrmA构造函数,重新引入了由TfrmA构造函数隐藏的签名.实际上,这不是对原始构造函数的重写,而是重新引入重新引入的构造函数.3)我觉得编译器应该发出关于这种隐藏的警告.它没有的原因可能是TfrmA构造函数的过载指令.当您删除它时,您会收到有关TfrmC.Create声明与前一声明不同的错误.4)由于TfrmC隐藏了TfrmA构造函数,编译器正确地抱怨TFrmC.Create(nil,0)具有太多参数.
当您使用override指令将TfrmA构造函数的签名添加到TfrmC时,2)中描述的内容变得很明显.然后,IDE会立即对此构造函数进行换行.原因:两个具有相同名称的构造函数和缺少重载指令的TfrmC构造函数只有AOwner参数.
当你在tfrmC的实例化中注释掉第二个参数并且只编码"inherited"时,它也变得清晰了.而不是"继承的创建(AOwner);" 在其实施中.编译器然后抱怨不兼容的类型.
后者可以通过使用"继承的Create(AOwner);"来解决.(正如你所做的那样)或"继承Create(AOwner,0);".虽然后者可以确保继承树继承,但前者会直接跳回到TForm1.Create.
使用稍微修改过的代码版本并提供TfrmC使用单个参数进行实例化,"继承Create(AOwner)"的结果将是:
alt text http://www.bjmsoftware.com/delphistuff/overloading/InheritedCreate1Param.jpg
而"继承Create(AOwner,0);"的结果 本来是: alt text http://www.bjmsoftware.com/delphistuff/overloading/InheritedCreate2Params.jpg
正如我在评论中建议的那样,为TfrmC构造函数添加重载会覆盖原始的TForm1.Create,并允许两个具有相同名称的构造函数.这可以通过打开TFRMC_OVERLOAD和INSTANTIATE2条件定义在测试项目中说明.这用TfrmC.Create(nil,0)实例化TfrmC并导致:
alt text http://www.bjmsoftware.com/delphistuff/overloading/InheritedCreate2ParamsOverload.jpg
其中显示TfrmB.Create被调用为TfrmC,因为TfrmB是第一个具有双参数构造函数实现的祖先.在使用TfrmC.Create(nil)实例化TfrmC时(将INSTANTIATE2条件定义关闭),产生与第一个或第二个相同的图像(取决于TWOPARAMS定义).
所有使用相同名称声明的方法都需要重载.范围是当前的类声明.
最简单的解决方案是overload
再次使用该指令:
type
TfrmC = class(TfrmB)
private
public
constructor Create(AOwner: TComponent); overload; override;
end;
Run Code Online (Sandbox Code Playgroud)
原因是因为原始构造函数TCustomForm
未声明为重载.