我是Delphi编码的新手,在尝试覆盖构造函数时遇到错误,你能告诉我我做错了什么或者我应该做些什么来达到预期的结果. 我想覆盖一个框架的构造函数,以便它可以将标签的Caption包含在特
我想覆盖一个框架的构造函数,以便它可以将标签的Caption包含在特定文本中.
这是代码
interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls; type TfrmMesaj = class(TFrame) Panel1: TPanel; private { Private declarations } public { Public declarations } constructor Create(name : string); override; end; implementation {$R *.dfm} { TfrmMesaj } { TfrmMesaj } constructor TfrmMesaj.Create(name: string); begin inherited; Panel1.Color := clRed; Panel1.Caption := name; end; end.
当我尝试编译时,我收到以下错误:
[DCC Error] frameMesaj.pas(17): E2037 Declaration of 'Create' differs from previous declaration [DCC Error] frameMesaj.pas(32): E2008 Incompatible types
我做错了什么,我怎么能得到我想要的?
Stefan解释了为什么你的覆盖不起作用.基本上,无论何时覆盖虚方法,两种方法的签名必须完全匹配.但是,我强烈反对使用重新引入.我将在这个答案的底部解释为什么. (请注意,重新引入非常具体,不会覆盖祖先方法.它只隐藏该方法隐藏祖先方法的警告.)几个更好的选择:
为构造函数使用不同的名称
您不必为构造函数Create命名.例如,您可以添加第二个构造函数:constructor CreateWithCaption(AName:string);.请注意,我甚至没有使这个构造函数虚拟化.如果您希望它们具有多态性,那么只能使方法成为虚拟方法. (这意味着您希望子类即使从基类调用也能够更改实现.)
这个选项非常像Stefan建议的重载.
使用工厂方法创建框架
随着系统变得越来越大,将创建一些对象的处理与他们实际执行的工作分开是很有用的.这是使用工厂方法完成的,其唯一目的是创建准备与系统其余部分交互的其他对象.例如.
//I've chosen to demonsrate this on a form, but you could also implement a dedicated factory class function TMyForm.CreateMessageFrame(ACaption: string): TFrame; begin //Note the factory method intends the form to own all frames created. Result := TfrmMesaj.Create(Self); //The factory method ensures the frame is "ready" //This does violate Law of Demeter, but you could easily add a method to the fram to resolve that. Result.Panel1.Color := clRed; Result.Panel1.Caption := ACaption; end;
重新引入有什么问题?
>重新引入仅适用于基类上的方法是虚拟的.
>如果打算以多态方式使用该方法,则该方法应该是虚拟的.
>这意味着该方法旨在从基类引用中调用,但可能需要采取特殊操作才能在某些子类中正常工作.
由于您的问题涉及覆盖TComponent.Create,因此通过示例的方式可以很好地说明.
>构造函数TComponent.Create(AOwner:TComponent);是非常具体的虚拟,因此组件创建的行为是多态的.这样,当从.DFM文件流式传输组件时,即使用于创建它们的引用是TComponent类型,也会正确创建它们.>如果隐藏此构造函数,则在从.DFM流式传输和创建帧时需要执行的任何特殊操作都不会发生.>此外,您帧的任何子类都无法覆盖构造函数Create(AOwner:TComponent);因为它是隐藏的.