更新:用一个更简单的例子扼杀了这个问题,但没有回答 按原来接受的答案
鉴于以下课程及其祖先:
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个构造函数可见:
我对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告诉我!
答案 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版本中使用。