Delphi:何时重新引入隐藏祖先以及何时显示它们?

发布于 2024-09-26 02:08:20 字数 3763 浏览 1 评论 0原文

今天 最近在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

放飞的风筝 2024-10-03 02:08:21

您不使用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 use reintroduce 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.

ゞ花落谁相伴 2024-10-03 02:08:21

您无法重写非虚拟方法,因此您没有隐藏任何内容。这就是为什么没有警告。

编辑:我会撤回我的断言“你没有隐藏任何东西”。我想我不太明白躲在这里的意义。我问了一个问题 对此。

更新:
基于答案我得到了,我想重新表述我的答案:由于 TComputer.Constructor 未声明为虚拟,因此您'我们已经从后代类中隐藏了该方法。因此,TCellPhone 构造函数无法隐藏根本不可见的内容,因此不会出现编译器警告。

You cannot override a method that's not virtual, so you're not hiding anything. That's why there's no warning.

edit: I'd withdraw my assertion "you're not hiding anything". I think I don't quite understand the meaning of hiding here. I've asked a quesiton on this.

update:
Based on the answer I got, I'd like to re-phrase my answer: Since TComputer.Constructor is not declared virtual, you've already hidden that method from descendant classes. So, TCellPhone constructors cannot hide what has not been visible at all, hence no compiler warning.

苦行僧 2024-10-03 02:08:21

好吧,看来您无法在重载的类中隐藏方法/构造函数。我用这个小小的“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 中被覆盖。 (我猜是极端情况错误,因为这不是一个非常常见的代码结构)

Well, it seems you can't hide a method/constructor in a class where you overload it as well. I came with this tiny "hack" to manage to hide the constructor from 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;

In that exemple, TiPhone will only have 1 constructor available. It does break the polymorphism though (a price to pay to hide the 2nd constructor from TCellPhone). I would like to know if anyone has found a way to do so without breaking the polymorphism.

Also, take note that it's not because the code insight show you 4 "constructors" that there is indeed 4 available. I noted that, for each "override" of the contructor, I would have 1 constructor listed in the code insight. But only the descendant constructor will be called in that situation.

This exemple will complain that the 2nd constructor of TCellPhone hide the one from THackComputer, but I think it's a false positive as the one from THackComputer is overriden in TCellPhone. (Corner case bug I guess, as this is not a very common code strucure)

魂归处 2024-10-03 02:08:21

我想将此作为对罗布·肯尼迪答案的评论,但由于我不能,所以我开始了..

始终没有关于隐藏祖先构造函数的警告。

很简单,因为你不这样做。

如果我隐藏祖先,为什么没有警告?我没有重新介绍。

再说一次,只是因为你没有隐藏任何东西。

你看到了你没有隐瞒任何事情的证据。您检查过的 3 个可用构造函数就是证明。

为什么可以用reintroduce来隐藏祖先?

就像 Rob 提到的那样,reintroduce 只是抑制编译器提示/警告。这个词背后没有真正的技术细节。因此,您不会通过重新引入隐藏任何内容。

我想谈谈如何隐藏,但我同意 Sertac 的观点,首先我必须知道在这种情况下你对隐藏的定义是什么。

编辑:
我刚刚读了你提到的帖子,我认为你误解了这些概念。这是我的简短解释。

reintroduce 用于隐藏祖先构造函数

该帖子的答案并不表明。真正隐藏祖先构造函数的是后代的 NEW CONSTRUCTOR,其参数与祖先构造函数相同。关键字重新引入只是抑制编译器警告。

reintroduce 用于显示祖先构造函数


那篇文章的答案是, OVERLOAD 关键字使祖先的构造函数仍然可用。

补充一下伊恩在下面的评论中提出的问题:

解决你的困惑的第一步是找出真正的问题。如果我们仔细检查您的帖子,就会发现您实际上想一步解决两个问题。这两个问题是:

  1. 隐藏具有特定名称的祖先构造函数
  2. 在后代中有多个具有相同特定名称的构造函数。

虽然它们看起来很简单,但是仔细观察就会立即让你意识到它们的性质是完全相反的。问题 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');

I wanted to put this as comment to Rob Kennedy's answer, but since I can't, here I go..

All the while there is no warning about hiding ancestor constructors.

Simply because you don't.

If i'm hiding the ancestor, why is there no warning? i have no reintroduce.

Again, simply because you don't hide anything.

You saw the proof that you did not hide anything. It's the 3 available constructors that you've inspected is the proof.

Why can reintroduce be used to hide the ancestor?

Like Rob mentioned, reintroduce is merely suppressing the compiler hint/warning. There is no real technicality behind that word. Thus you don't hide anything with reintroduce.

I would like to put my thought on how to hiding, but I agree with Sertac, first I have to know what is your definition of hiding in this case.

Edit:
I just read the posts you mentioned, I think you have misunderstood the concepts. Here my short explanation.

reintroduce is used to hide ancestor constructors

The answer of that post does not indicate that. The one that really hiding ancestor's constructor is the NEW CONSTRUCTOR of the descendant with the same parameter with the ancestor's. The keyword reintroduce is simply suppressing compiler warning.

reintroduce is used to show ancestor constructors

In the answer of that post, it's the OVERLOAD keyword that makes ancestor's constructor still available.

ADDITION in response to Ian's question in his comment below:

The first step to solve your confusion is to identify the real problems. If we carefully examine you posts, it will become obvious that you actually wanted to solve two problems in one step. The two problems are:

  1. To hide ancestor constructor with specific name
  2. To have multiple constructor with same specific name in the descendant.

Although they may seem simple problems, but careful inspection will immediately struck your head that their natures are exactly opposite to each other. Problem 1 wants to hide a method/constructor while problem 2 wants to show not only one but multiple method/constructor. So if you mix them together in one step, they will definitely cancel each others out. No wonder they give you headache... :)

The basic rule to solve these two problems is not to mix them in one step. This means we need an intermediate class to solve problem 1, and do the overloading in descendants of that intermediate class. Something like this:

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;

From the above code, TBaseCellphone is the intermediary class. In this scenario its task is solely to hide the constructor Create of TComputer. Please note that you MUST NOT use overload keyword here, or the hiding will be canceled. Now after the hiding is done, now you can freely spam your overload keyword in its descendants to get multiple constructor with same name.

To check, you can see that the following code will not compile:

   TCellPhone.Create('My Teapot');
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文