Delphi:如何隐藏祖先构造函数?

时间:2010-10-06 15:46:50

标签: delphi constructor delphi-5 constructor-chaining

  

更新:用一个更简单的例子扼杀了这个问题,但没有回答   按原来接受的答案

鉴于以下课程及其祖先:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

现在TCellPhone有3个构造函数可见:

  • 杯子:整数
  • 杯子:整数;茶壶:字符串
  • 茶壶:string =''

我对TCellPhone做了什么,以便祖先构造函数(Teapot: string = '')不可见,只留下声明的构造函数:

  • 杯子:整数
  • 杯子:整数;茶壶:字符串
  

注意:通常拥有后代构造函数的简单行为会隐藏祖先:

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); virtual;
end;
     
      
  • 杯子:整数
  •   
     

如果你希望同时保留两者   祖先构造函数和   后代,你会标记   后代为overload

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
end;
     
      
  • 杯子:整数
  •   
  • 茶壶:string =''
  •   

在这个问题的示例代码中,Delphi误解了我的overload关键字:

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

认为:

  • 我想用祖先
  • 重载我的构造函数
  • 当我真的想用兄弟
  • 超载它时

如何隐藏祖先构造函数?

注意:可能无法使用当前定义的Delphi语言隐藏祖先,非虚拟构造函数。 “不可能” 是一个有效的答案。


尝试答案(失败)

尝试使用reintroduce标记后代构造函数(回到我随机添加关键字的模式,直到它起作用):

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); reintroduce; overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
end;

但这不起作用,所有三个构造函数仍然可见。 :(


原始问题

我有一个对象,它来自一个有构造函数不想看的类:

TEniac = class(TObject)
   constructor Create(PowerCord: TPowerCord=nil); //calls inherited Create

TComputer = class(TEniac) ...
   constructor Create(PowerCord: TPowerCord=nil); //calls inherited Create(nil)

TCellPhone = class(TComputer)
   constructor Create(sim: TSimChip; UnlockCode: Integer); //calls inherited Create(nil)

TiPhone = class(TCellPhone)
   constructor Create(sim: TSimChip); //calls inherited Create(sim, 0)
  

注意:这是一个假设的例子。与现实世界一样,如果不破坏现有代码,则无法更改祖先对象。

现在当有人使用TiPhone时我甚至不希望他们从<{1}} 看到构造函数:

TEniac

更糟糕的是:如果他们调用那个构造函数,他们会完全错过我的构造函数,并且完成所有工作。调用错误的构造函数非常容易,所有这些都在IDE代码完成中可见,并将编译:

iphone := TiPhone.Create(powerCord);

他们得到一个完全无效的对象。

我可以更改TiPhone.Create; 以在这些构造函数中抛出异常:

TCellPhone

但是开发人员不会意识到他们正在调用错误的构造函数,直到客户有一天发现错误并罚款我们的bazillions美元。事实上,我 尝试 找到我称之为错误构造函数的所有地方 - 但我无法弄清楚如何让Delphi告诉我!

6 个答案:

答案 0 :(得分:6)

如果我没记错,那么reintroduce应该有助于虚拟方法。

  

重新引入指令禁止编译器警告隐藏先前声明的虚拟方法。   如果要使用新方法隐藏继承的虚拟方法,请使用重新引入。

要回答您更新的问题 - 我认为隐藏非虚拟构造函数并不可能在直接派生类中进行重载,但我尝试了以下成功:

TComputer = class(TObject)
public
  constructor Create(Teapot: string='');
end;

TIndermediateComputer = class(TComputer)
protected
  // hide the constructor
  constructor Create;
end;

TCellPhone = class(TIndermediateComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

答案 1 :(得分:6)

为了在Delphi中创建派生类,不可能在祖先中引入构造函数,因为你总是可以这样做:

type
  TComputerClass = class of TComputer;

var
  CellPhoneClass: TComputerClass = TCellPhone;
  CellPhone : TCellPhone;
begin
  CellPhone := CellPhoneClass.Create('FUBAR') as TCellPhone;
end;

在任何派生类的代码中你都无法阻止任何人调用TComputer.Create构造函数来创建派生类的实例。

你能做的最好的事情是:

TComputer = class(TObject)
public
   constructor Create(Teapot: string=''); virtual;
end;

TCellPhone = class(TComputer)
public
   constructor Create(Teapot: string=''); overload; override;
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

在这种情况下,上面的代码至少会调用TCellPhone.Create(Teapot: string='')而不是TComputer.Create(Teapot: string='')

答案 2 :(得分:4)

除非声明为虚拟或动态,否则无法隐藏父类的构造函数。但是,您可以阻止从子类中调用它。考虑一下你的例子:

TComputer = class(TObject)
public
   constructor Create(Teapot: string='');
end;

TCellPhone = class(TComputer)
public
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

TComputer.Create始终可见TCellPhone。您可以通过声明具有相同签名的TComputer.Create来阻止TCellPhone.Create被无意调用。

TCellPhone = class(TComputer)
public
   constructor Create(Teapot: string='');
   constructor Create(Cup: Integer); overload; virtual;
   constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;

然后,只要您在inherited的正文中没有调用TCellPhone.Create(Teapot: string=''),就可以阻止在TComputer.Create及其后代中调用TCellPhone。以下内容:

TCellphone.Create;
TCellphone.Create('MyPhone');

将解决TCellPhone的实施问题。

此外:

TiPhone = class(TCellPhone)
    constructor Create;
end;

constructor TiPhone.Create;
begin
  inherited;
end;

将调用TCellPhone.Create而非TComputer.Create

答案 3 :(得分:3)

不要仅在重写的无效构造函数中引发“不使用”异常,而应考虑在它们变为无效的类中将它们标记为已弃用。当错误地使用这些无效的构造函数时,这应该产生很好的编译器警告。

TCellPhone = class(TComputer)
   constructor Create(PowerCord: TPowerCord=nil); deprecated;
   constructor Create(sim: TSimChip; UnlockCode: Integer); //calls inherited Create(nil)

此外,根据需要使用覆盖或重新引入。

答案 4 :(得分:1)

您想要重新引入构造函数:

TiPhone = class(TCellPhone)
    constructor Create(sim: TSimChip); reintroduce;

请参阅Delphi源代码中的TComponent.Create以获取此实例。

答案 5 :(得分:1)

我知道这是一个5岁的话题,但它仍然可以帮助某人。 隐藏祖先构造函数的唯一方法是将两个Create方法中的一个重命名为其他方法,并删除 overload 指令的需要。 它看起来很奇怪,但这是唯一的方法。至少在旧版本的Delphi中。我不知道现在是否可以在XE xxx版本中使用。