Delphi:何时重新引入隐藏祖先以及何时显示它们?
今天 最近在 Stackoverflow 上我了解到:
我一直在尝试理解这一切,所以这是另一个,非常具体的问题,支持我处理构造函数的主要问题。
更新:替换了整个问题:
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 = '']
问题:为什么 constructor(Teapot: string='')
没有被隐藏?
现在我添加了第三个后代:
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;
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); override;
end;
构建TiPhone
时四个可用的构造函数:
- Cup: Integer
- Cup: Integer
- Cup: Integer; Teapot: string
- [Teapot: string = '']
为什么有四个构造函数?我覆盖了现有的三个之一。 编辑:这可能是代码洞察中的一个错误,它向我显示了四个 - 但当两个相同时我怎么可能调用呢。
再次使用原始代码:
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
有三个构造函数:
- Cup: Integer
- Cup: Integer; Teapot: string
- [Teapot: String = '']
如何更改 TCellPhone
的声明以隐藏祖先构造函数?例如:
TNokia = class(TCellPhone)
end;
只有两个构造函数:
- Cup: Integer
- Cup: Integer; Teapot: string
现在介绍使用 reintroduce
隐藏非虚拟祖先的情况。在前面的例子中,TiPhone
有四个构造函数(理想情况下只有两个 - TComputer
以某种方式隐藏了它的祖先)。但即使我无法修复 TComputer
,我也可以将 TiPhone
更改为只有一个:
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;
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); reintroduce;
end;
现在 TiPhone
只有一个构造函数:
- Cup: Integer
Reintroduce 通常仅用于抑制有关隐藏虚拟祖先的警告。在这种情况下:
Create(Teapot: string = '')
不是虚拟的 - 但我仍然可以使用重新引入来隐藏它。
但是现在,如果我向TiPhone
添加另一个重载:
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); reintroduce; overload;
constructor Create(Handle: String); overload;
end;
然后突然(之前隐藏的)祖先回来了:
- TiPhone.Create(7);
- TiPhone.Create('粉红色');
- TiPhone.Create(7, '粉红色');
- TiPhone.Create();
的逻辑
- 正如你所看到的,我正在努力理解当某些东西被隐藏时
- 如何隐藏某些东西
- 当某些东西被显示时
- 如何显示某些东西
Today Recently on Stackoverflow i learned that:
i've been trying to make sense of it all, so here is a another, very specific question, supporting my main question dealing with constructors.
Update: replaced the entire question:
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;
When constructing TCellPhone, 3 constructors are avaible:
- Cup: Integer
- Cup: Integer; Teapot: string
- [Teapot: String = '']
Question: Why is constructor(Teapot: string='')
not being hidden?
Now i added a 3rd descendant:
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;
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); override;
end;
When constructing TiPhone
four constructors are available:
- Cup: Integer
- Cup: Integer
- Cup: Integer; Teapot: string
- [Teapot: string = '']
Why are there four constructors? i overrode one of the existing three. Edit: This may be a bug in code-insight, it shows me four - yet how could i possibly call then when two are the same.
Using the original code again:
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;
it's already known that TCellPhone
has three constructors:
- Cup: Integer
- Cup: Integer; Teapot: string
- [Teapot: String = '']
How do i alter the declaration of TCellPhone
to hide the ancestor constructor? e.g. so that:
TNokia = class(TCellPhone)
end;
will only have two constructors:
- Cup: Integer
- Cup: Integer; Teapot: string
Now for the case where reintroduce
is used to hide a non-virtual ancestor. In the previous case TiPhone
has four constructors (ideally there would be only two - with TComputer
somehow hiding its ancestor). But even if i can't fix TComputer
, i can change TiPhone
to only have the one:
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;
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); reintroduce;
end;
Now TiPhone
has only one constructor:
- Cup: Integer
Reintroduce is normally only used to suppress the warning about hiding virtual ancestors. In this case:
Create(Teapot: string = '')
isn't virtual - yet i can still use reintroduce to hide it.
But now, if i add another overloaded to TiPhone
:
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); reintroduce; overload;
constructor Create(Handle: String); overload;
end;
Then suddenly the (previously hidden) ancestors come back:
- TiPhone.Create(7);
- TiPhone.Create('pink');
- TiPhone.Create(7, 'pink');
- TiPhone.Create();
As you can see, i'm struggling to understand the logic of
- when something is hidden
- how to hide something
- when something is shown
- how to show something
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

发布评论
评论(4)
好吧,看来您无法在重载的类中隐藏方法/构造函数。我用这个小小的“hack”来设法从 TComputer 中隐藏构造函数
TComputer = class(TObject)
public
constructor Create(Teapot: string='');
end;
THackComputer = class(TComputer)
public
constructor Create(Cup : Integer);virtual;
end;
TCellPhone = class(THackComputer)
public
constructor Create(Cup: Integer); overload; override;
constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); reintroduce; virtual;
end;
。在该示例中,TiPhone 将只有 1 个可用的构造函数。但它确实打破了多态性(从 TCellPhone 中隐藏第二个构造函数所付出的代价)。我想知道是否有人找到了一种方法可以在不破坏多态性的情况下做到这一点。
另外,请注意,并不是因为代码洞察显示了 4 个“构造函数”,所以确实有 4 个可用。我注意到,对于构造函数的每个“覆盖”,我都会在代码洞察中列出 1 个构造函数。但在这种情况下,只会调用后代构造函数。
这个例子会抱怨 TCellPhone 的第二个构造函数隐藏了来自 THackComputer 的构造函数,但我认为这是一个误报,因为来自 THackComputer 的构造函数在 TCellPhone 中被覆盖。 (我猜是极端情况错误,因为这不是一个非常常见的代码结构)
我想将此作为对罗布·肯尼迪答案的评论,但由于我不能,所以我开始了..
始终没有关于隐藏祖先构造函数的警告。
很简单,因为你不这样做。
如果我隐藏祖先,为什么没有警告?我没有重新介绍。
再说一次,只是因为你没有隐藏任何东西。
你看到了你没有隐瞒任何事情的证据。您检查过的 3 个可用构造函数就是证明。
为什么可以用reintroduce来隐藏祖先?
就像 Rob 提到的那样,reintroduce 只是抑制编译器提示/警告。这个词背后没有真正的技术细节。因此,您不会通过重新引入隐藏任何内容。
我想谈谈如何隐藏,但我同意 Sertac 的观点,首先我必须知道在这种情况下你对隐藏的定义是什么。
编辑:
我刚刚读了你提到的帖子,我认为你误解了这些概念。这是我的简短解释。
该帖子的答案并不表明。真正隐藏祖先构造函数的是后代的 NEW CONSTRUCTOR,其参数与祖先构造函数相同。关键字重新引入只是抑制编译器警告。
那篇文章的答案是, OVERLOAD 关键字使祖先的构造函数仍然可用。
补充一下伊恩在下面的评论中提出的问题:
解决你的困惑的第一步是找出真正的问题。如果我们仔细检查您的帖子,就会发现您实际上想一步解决两个问题。这两个问题是:
- 隐藏具有特定名称的祖先构造函数
- 在后代中有多个具有相同特定名称的构造函数。
虽然它们看起来很简单,但是仔细观察就会立即让你意识到它们的性质是完全相反的。问题 1 想要隐藏一个方法/构造函数,而问题 2 想要不仅显示一个方法/构造函数,而且还显示多个方法/构造函数。因此,如果您一步将它们混合在一起,它们肯定会相互抵消。难怪它们让你头疼……:)
解决这两个问题的基本规则是不要将它们混合在一起。这意味着我们需要一个中间类来解决问题 1,并在该中间类的后代中进行重载。是这样的:
type
TComputer = class(TObject)
private
FCaller: TConstructorCaller;
public
constructor Create(Teapot: string=''); virtual;
property Caller: TConstructorCaller read FCaller;
end;
TBaseCellphone=class(TComputer)
constructor Create(Cup: Integer); virtual;
end;
TCellPhone = class(TBaseCellphone)
protected
public
constructor Create(Cup: Integer); overload; override;
constructor Create(Cup: Integer; Teapot: string); overload; virtual;
end;
TiPhone = class(TCellPhone)
public
constructor Create(Cup: Integer); reintroduce; overload;
constructor Create(Handle: String); reintroduce; overload;
end;
从上面的代码来看,TBaseCellphone 是中间类。在这种情况下,它的任务只是隐藏 TComputer 的构造函数 Create。请注意,您不得在此处使用重载关键字,否则隐藏将被取消。现在,隐藏完成后,您可以在其后代中自由地发送重载关键字,以获得多个具有相同名称的构造函数。
检查一下,可以看到下面的代码无法编译:
TCellPhone.Create('My Teapot');
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
您不使用
reintroduce
来隐藏祖先类的方法。您只需声明一个与祖先类中的方法同名的方法即可实现此目的,而无需覆盖或重载它。当祖先类的方法(被隐藏的方法)是虚拟的时,您可以使用reintroduce
来抑制Delphi发出的警告。如果后代的方法覆盖祖先的方法,那么它就不会隐藏。对祖先方法的调用将被路由到后代方法。
如果后代的方法重载祖先的方法,那么它也不会隐藏。两者均可致电。
You don't use
reintroduce
to hide a method of an ancestor class. You do that simply by declaring a method with the same name as one in the ancestor class without overriding or overloading it. You usereintroduce
to suppress the warning that Delphi raises when the ancestor class's method (the one being hidden) is virtual.If the descendant's method overrides the ancestor's, then it's not hiding. Calls to the ancestor's method are routed to the descendant's instead.
If the descendant's method overloads the ancestor's, then it's also not hiding. Both are available to call.