我是Delphi编码的新手,在尝试覆盖构造函数时遇到错误,你能告诉我我做错了什么,或者我应该做些什么来达到理想的结果。
我想覆盖一个框架的构造函数,以便它可能会将标签的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
我做错了什么,我怎么能得到我想要的东西?
答案 0 :(得分:8)
Stefan解释了为什么你的覆盖不起作用。基本上,无论何时覆盖虚方法,两种方法的签名必须完全匹配。但是,我强烈反对使用reintroduce
。我将在这个答案的底部解释为什么。 (另请注意重新引入非常具体 不会 覆盖祖先方法。只有 隐藏警告 该方法 隐藏 祖先的方法。)
有两个更好的选择:
您不必为构造函数Create
命名。例如,您可以添加第二个构造函数:constructor CreateWithCaption(AName: string);
。请注意,我甚至没有使这个构造函数虚拟化。如果您希望它们以多态行为,则仅使方法成为虚拟方法。 (这意味着您希望子类即使从基类调用也能够更改实现。)
此选项与Stefan建议的重载非常相似。
随着系统变得越来越大,将创建某些对象的处理与他们实际执行的工作分开是很有用的。这是使用工厂方法完成的,其唯一目的是创建准备与系统其余部分交互的其他对象。 E.g。
//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;
reintroduce
还有什么问题?由于您的问题涉及覆盖TComponent.Create
,因此通过示例的方式很好地说明了这一点。
constructor TComponent.Create(AOwner: TComponent);
非常具体地虚拟,因此组件创建的行为是多态的。这样,当从.DFM文件流式传输组件时,即使用于创建它们的引用的类型为TComponent
,也会正确创建 。< / LI>
constructor Create(AOwner: TComponent);
,因为它已被隐藏。答案 1 :(得分:5)
TFrame
的构造函数如下所示:
constructor Create(AOwner: TComponent); virtual;
如果你想要override
,你必须保留签名:
constructor Create(AOwner: TComponent); override;
如果您想添加自己的版本,提供overload
所需的名称,以便两个版本并排存在:
constructor Create(name: string); reintroduce; overload; // see Edit below
如果你想隐藏你需要写的虚拟的reintroduce
(不推荐):
constructor Create(name: string); reintroduce;
修改强>
当您重载虚拟方法时,即使不隐藏虚拟方法,也需要reintroduce
。这已在此处报告和讨论:http://qc.embarcadero.com/wc/qcmain.aspx?d=106026
答案 2 :(得分:0)
为什么不简单地使用OnCreeate事件而不是尝试覆盖默认的Constructor方法。
在您的情况下,OnCreate事件就足够了,因为您没有对TFrame组件本身进行任何重要更改,而只是对其上放置的其他组件进行了任何重要更改。