Delphi:如何隐藏祖先构造函数?
更新:用一个更简单的例子来解决这个问题,但没有得到回答 根据最初接受的答案
给定以下类及其祖先:
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 个可见的构造函数:
- Cup: Integer
- Cup: Integer; Teapot: string
- Teapot: string = ''
我该如何处理 TCellPhone
以便祖先构造函数 (Teapot: string = ''
) 不可见,只留下声明的构造函数:
- Cup: Integer
- Cup: Integer;茶壶: 串
注意:通常拥有后代构造函数的简单行为会隐藏祖先:
TCellPhone = 类(TComputer) 民众 构造函数 Create(Cup: Integer);虚拟的; 结尾;
- 杯数:整数
如果您想要同时保留 祖先构造函数和 后代,你会标记 后代作为
重载
:TCellPhone = 类(TComputer) 民众 构造函数 Create(Cup: Integer);超载;虚拟的; 结尾;
- 杯数:整数
- 茶壶: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
时,我什至不希望他们能够看到来自 TEniac
的构造函数:
iphone := TiPhone.Create(powerCord);
更糟糕的是:如果他们调用该构造函数,他们完全想念我的构造函数,以及其间所做的一切。调用错误的构造函数非常容易,所有这些构造函数在 IDE 代码完成中都是可见的,并且会编译:
TiPhone.Create;
并且它们会得到一个完全无效的对象。
我可以更改 TCellPhone
以在这些构造函数中引发异常:
TCellPhone.Create(PowerCord: TPowercord)
begin
raise Exception.Create('Don''t use.');
end;
但开发人员不会意识到他们调用了错误的构造函数,直到有一天客户发现错误并向我们罚款数百万美元。事实上,我试图找到我调用错误构造函数的所有地方 - 但我不知道如何让 Delphi 告诉我!
Update: gutted the question with a simpler example, that isn't answered
by the originally accepted answer
Given the following class, and its ancestor:
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;
Right now TCellPhone
has 3 constructors visible:
- Cup: Integer
- Cup: Integer; Teapot: string
- Teapot: string = ''
What do i do to TCellPhone
so that the ancestor constructor (Teapot: string = ''
) is not visible, leaving only the declared constructors:
- Cup: Integer
- Cup: Integer; Teapot: string
Note: Usually the simple act of having a descendant constructor hides the ancestor:
TCellPhone = class(TComputer) public constructor Create(Cup: Integer); virtual; end;
- Cup: Integer
And if you wanted to keep both the
ancestor constructor and the
descendant, you would mark the
descendant as anoverload
:TCellPhone = class(TComputer) public constructor Create(Cup: Integer); overload; virtual; end;
- Cup: Integer
- Teapot: string = ''
In this question's example code, Delphi is mistaking my overload
keywords:
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer); overload; virtual;
constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;
to think that:
- i want to overload my constructors with the ancestor,
- when really i want to overload it with the sibling
How do i hide the ancestor constructor?
Note: It might be impossible to hide the ancestor, non-virtual, constructor using the Delphi language as it is currently defined. "Not possible" is a valid answer.
Attempted Answer (failed)
i tried marking the descendant constructors with reintroduce
(falling back to my mode of randomly adding keywords until it works):
TCellPhone = class(TComputer)
public
constructor Create(Cup: Integer); reintroduce; overload; virtual;
constructor Create(Cup: Integer; Teapot: string); reintroduce; overload; virtual;
end;
But that didn't work, all three constructors are still visible. :(
Original Question
i have an object that descends from a class that has constructors don't want to see:
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)
Note: This is a hypothetical example. As in the real world, the ancestor objects cannot be changed without breaking existing code.
Now when someone's using TiPhone
i don't want them even being able to see the constructor from TEniac
:
iphone := TiPhone.Create(powerCord);
Worse still: if they call that constructor, they completely miss my constructor, and everything done in between. It's pretty easy to call the wrong constructor, all of them are visible in the IDE code-completion, and will compile:
TiPhone.Create;
and they get a completely invalid object.
i could change TCellPhone
to throw an exception in those constructors:
TCellPhone.Create(PowerCord: TPowercord)
begin
raise Exception.Create('Don''t use.');
end;
But developers won't realize they're calling the wrong constructor until the customer finds the error one day and fines us bazillions of dollars. In fact, i'm trying to find everywhere i call the wrong constructor - but i can't figure out how to make Delphi tell me!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
在 Delphi 中创建派生类时,不可能使祖先中引入的构造函数无法访问,因为您始终可以这样做:
您在任何派生类的代码中所做的任何事情都无法阻止任何人调用 TComputer .创建构造函数来创建派生类的实例。
您可以做的最好的事情是:
在这种情况下,上面的代码至少会调用
TCellPhone.Create(Teapot: string='')
而不是TComputer.Create(Teapot: string=' ')
It's impossible to ever make a constructors introduced in an ancestor inaccessible for the creation of a derived class in Delphi because you can always do this:
Nothing you could do in the code of any derived class would ever be able to prevent anyone from calling the TComputer.Create constructor for creating an instance of the derived class.
The best you could do is:
In that case the code above would at least be calling
TCellPhone.Create(Teapot: string='')
instead ofTComputer.Create(Teapot: string='')
如果我没记错的话,那么
reintroduce
应该有助于虚拟方法。要回答您更新的问题 - 我认为不可能在直接派生类中隐藏具有重载的非虚拟构造函数,但我成功地尝试了以下操作:
If I remember correctly, then
reintroduce
should help for virtual methods.To answer your updated question - I think it's not possbile to hide a non-virtual constructor with overloading in a directly derived class, but I tried the following successfully:
不要只在重写的无效构造函数中引发“不要使用”异常,而是考虑在它们变得无效的类中将它们标记为已弃用。当错误地使用这些无效的构造函数时,这应该会产生很好的编译器警告。
此外,根据需要使用覆盖或重新引入。
Instead of only raising an "Don't use" exception in the overridden invalid constructors, consider marking them deprecated in the class where they become invalid. That should produce nice compiler warnings when these invalid constructors are used erroneosly.
In addition, use override or reintroduce as needed.
除非将父类的构造函数声明为虚拟的或动态的,否则您无法隐藏它。但是,您可以阻止从子类中调用它。考虑您的示例:
TComputer.Create
将始终在TCellPhone
中可见。您可以通过声明具有相同签名的TCellPhone.Create
来防止意外调用TComputer.Create
。然后,只要您在
TCellPhone.Create(Teapot: string='')
正文中没有调用inherited
,就可以阻止TComputer.通过在
。以下内容:TCellPhone
及其后代中调用来创建将解决 TCellPhone 的实现。
另外:
将调用
TCellPhone.Create
而不是TComputer.Create
。You can't hide the parent class' constructor unless it was declared virtual or dynamic. You can however prevent it from being called from the child class. Consider your example:
TComputer.Create
will always be visible fromTCellPhone
. You can preventTComputer.Create
from being inadvertantly called by declaring aTCellPhone.Create
with the same signature.Then as long as you don't have a call to
inherited
in the body ofTCellPhone.Create(Teapot: string='')
you can preventTComputer.Create
from being called inTCellPhone
and its descendants. The following:Will resolve to TCellPhone's implementation.
Additionally:
Will invoke
TCellPhone.Create
and notTComputer.Create
.您想要重新引入构造函数:
请参阅 Delphi 源代码中的
TComponent.Create
以获取实际示例。You want to reintroduce the constructor:
See
TComponent.Create
in the Delphi source code for a real-world example of this.我知道这是 5 年前的话题,但它仍然可能对某人有所帮助。overload 指令的需要。
隐藏祖先构造函数的唯一方法是将两个 Create 方法之一重命名为其他方法,并消除对
看起来很奇怪,但这是唯一的方法。至少在旧版本的 Delphi 中是这样。我不知道 XE xxx 版本现在是否可以。
I know that this is 5 years old topic, but still it may help someone.
The only way to hide the ancestor's constructor is to rename one of the two Create methods to something else and remove the need of overload directive.
It looks weird but it's the only way. At least in older versions of Delphi. I don't know is it possible now in the XE xxx versions.