覆盖构造错误

时间:2014-05-22 12:25:23

标签: delphi constructor override

我是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

我做错了什么,我怎么能得到我想要的东西?

3 个答案:

答案 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>
  • 如果隐藏此构造函数,则在流式传输和从.DFM创建帧时需要执行的任何特殊操作都不会发生。
  • 您的框架的任何子类 将无法 覆盖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组件本身进行任何重要更改,而只是对其上放置的其他组件进行了任何重要更改。