Delphi/pascal:用不同的原型重载构造函数

Posted

技术标签:

【中文标题】Delphi/pascal:用不同的原型重载构造函数【英文标题】:Delphi/pascal: overloading a constructor with a different prototype 【发布时间】:2010-12-18 01:14:45 【问题描述】:

我正在尝试使用

创建 TForm 的子类
    特定情况下的特殊构造函数,以及 默认构造函数,将保持与当前代码的兼容性。

这是我现在的代码:

interface
  TfrmEndoscopistSearch = class(TForm)
  public
    /// original constructor kept for compatibility
    constructor Create(AOwner : TComponent); overload; override;
    /// additional constructor allows for a caller-defined base data set
    constructor Create(AOwner : TComponent; ADataSet : TDataSet; ACaption : string = ''); overload;
  end;

它似乎工作,但我总是得到编译器警告:

[警告] test.pas(44): 方法 'Create' 隐藏了基本类型 'TCustomForm' 的虚拟方法 添加“重载;”在第二个构造函数不会编译之后。 “[Error] test.pas(44): 'Create' 的声明与之前的声明不同”。 使第二个构造函数成为类函数编译时不会出现任何错误或警告,但会在运行时因访问冲突而终止(所有成员 var 均为 nil)。

【问题讨论】:

【参考方案1】:

有一个非常简单的方法可以避免这种情况。 为您的新构造函数起一个不同的名称。 与其他一些流行语言不同,Delphi 有命名构造函数;您不必称它们为 Create。您可以调用新的 CreateWithDataset 而完全不干扰虚拟 Create 构造函数。

TfrmEndoscopistSearch = class(TForm)
  /// original constructor kept for compatibility
  constructor Create(AOwner: TComponent); override;
  /// additional constructor allows for a caller-defined base data set
  constructor CreateWithDataset(AOwner: TComponent; ADataSet: TDataSet; ACaption: string = '');
end;

事实上,除非你以多态方式实例化这个类,否则你甚至不需要原来的构造函数。你可以这样声明你的新的:

TfrmEndoscopistSearch = class(TForm)
  /// additional constructor allows for a caller-defined base data set
  constructor Create(AOwner: TComponent; ADataSet: TDataSet; ACaption: string = ''); reintroduce;
end;

尝试直接在 TfrmEndoscopistSearch 上调用单参数构造函数会产生编译错误。


(以多态方式创建它通常需要使用 Application.CreateForm:

Application.CreateForm(TfrmEndoscopistSearch, frmEndoscopistSearch);

这总是调用 TComponent 中引入的单参数虚拟构造函数。除非它是您的主要形式,否则您不需要这样做。我之前写过my feelings on Application.CreateForm。)

【讨论】:

这可能是最合适的解决方案,但它不是问题的答案。练习的一部分是解决问题,而不必更改已经使用一种或另一种形式的 create() 的其他 10 多个文件中的任何一个。我将这个表单从两个不同的项目合并在一起,不想分叉。 答案是有效的,但可能有点危险。如果第 3 方用户使用他可能会调用(意外)标准构造函数 (Create) 而不是新构造函数的代码。 我不明白这怎么能被认为是“危险的”,@Migrate。在我的回答中,我指出保留原始构造函数是为了兼容。也就是说,它是为了与想要调用原始构造函数的代码兼容。如果这样做是合法的,那么就无法判断这是否是“偶然的”。 但是,如果兼容性不是问题,那么这个答案中的第二个代码块已经演示了如何防止人们在有限的情况下调用原始构造函数。那么危险在哪里?【参考方案2】:

尝试在第二个overload 之前添加reintroduce,如下所示:

  TfrmEndoscopistSearch = class(TForm)
  public
    /// original constructor kept for compatibility
    constructor Create(AOwner : TComponent); overload; override;
    /// additional constructor allows for a caller-defined base data set
    constructor Create(AOwner : TComponent; ADataSet : TDataSet; ACaption : string = ''); reintroduce; overload;
  end;

这在 Turbo Delphi 中编译。我需要public 来编译它,因为published 方法的重载受到限制。

【讨论】:

砰! “reintroduce”关键字正是我们所需要的。还需要原始构造函数,因为它将数据集设置为正确的默认值。 周围的人仍然想知道关键字背后的魔力,“重载”是因为我们在同一个类中有两个同名的函数(构造函数)。 “覆盖”是因为第一个构造函数覆盖了原来的构造函数(在父类中),而“重新引入”是关闭编译器警告(我们告诉编译器“没关系,我知道我在做什么。这不是错误.").【参考方案3】:
constructor Create(AOwner:Tcomponent;str:string);overload;
... 
constructor TfrmEndoscopistSearch.Create(AOwner: Tcomponent; str: string);
    begin
    inherited Create(AOwner);
    showmessage(str);
    end;

这应该可以解决问题

【讨论】:

以上是关于Delphi/pascal:用不同的原型重载构造函数的主要内容,如果未能解决你的问题,请参考以下文章

函数重载分析

JavaScript 原型对象原型链

Delphi/Pascal 有静态代码分析工具吗? [关闭]

拷贝构造函数——重载赋值运算符

JavaScript面向对象精要

函数重载与复制构造函数