重新引入构造函数的可见性

时间:2010-05-17 10:52:45

标签: 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;

创建时:

  frmA := TfrmA.Create(nil, 0);
  frmB := TfrmB.Create(nil, 0);
  frmC := TfrmC.Create(nil, 0); // Compiler error

我的解决方法是覆盖重新引入的构造函数或声明原始构造函数重载,但我想了解这种行为的原因。

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;

2 个答案:

答案 0 :(得分:7)

在初始代码中,您的Create构造函数会隐藏原始Create。这就是为什么编译器抱怨TfrmC重写一个它再也看不到的构造函数了。

您通常会收到有关此内容的编译器消息,但“重新引入”会抑制此情况。每当您需要“重新引入”来抑制编译器消息时,警报响应就会消失,因为它表明您正在打破多态性。并不意味着你不应该使用它,但你应该意识到其含义。

在这些情况下,如果我想保留覆盖原始构造函数的能力,我倾向于添加不同的构造函数,即

constructor CreateWithParent(AOwner: TComponent; const AWndParent: HWnd); virtual;

并在其实现中调用原始构造函数。它确实意味着我需要调用一个不同的构造函数,但是你已经需要传递另一个参数,这似乎不是一个糟糕的权衡。

编辑: 正如我在评论中提到的,编译器抱怨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);”在其实施中。编译器然后抱怨不兼容的类型。

后者可以通过使用“inherited Create(AOwner);”来解决。 (正如你所做的那样)或“继承Create(AOwner,0);”。虽然后者可以确保继续使用继承树,但前者会直接跳回到TForm1.Create。

使用稍微修改后的code版本,并且提供的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

其中显示为TfrmC调用TfrmB.Create,因为TfrmB是第一个具有双参数构造函数实现的祖先。在使用TfrmC.Create(nil)实例化TfrmC时(将INSTANTIATE2条件定义关闭),得到的图像与第一个或第二个相同(取决于TWOPARAMS定义)。

答案 1 :(得分:5)

所有使用相同名称声明的方法都需要重载。范围是当前的类声明。

最简单的解决方案是再次使用overload指令:

type
  TfrmC = class(TfrmB)
  private
  public
    constructor Create(AOwner: TComponent); overload; override;
  end;

原因是因为TCustomForm中的原始构造函数未被声明为重载。