“方法‘%s’”隐藏基类型“%s”的虚拟方法。到底隐藏了什么?

发布于 2024-09-26 14:08:17 字数 1956 浏览 2 评论 0原文

阅读 Ian Boyd 的构造函数系列问题后 (1, 2, < a href="https://stackoverflow.com/questions/3876484/delphi-how-to-add-a- Different-constructor-to-a-descendant">3, 4),我意识到我不太明白隐藏内容的字面意思。

我知道(如果我错了,请纠正我)override 的唯一目的是能够具有多态行为,以便运行时可以根据实例的实际类型解析方法 -与声明的类型相反。考虑以下代码:

type
  TBase = class
    procedure Proc1; virtual;
    procedure Proc2; virtual;
  end;

  TChild = class(TBase)
    procedure Proc1; override;
    procedure Proc2;            // <- [DCC Warning]
  end;

procedure TBase.Proc1;
begin
  Writeln('Base.Proc1');
end;
procedure TBase.Proc2;
begin
  Writeln('Base.Proc2');
end;

procedure TChild.Proc1;
begin
  inherited Proc1;
  Writeln('Child.Proc1');
end;
procedure TChild.Proc2;
begin
  inherited Proc2;
  Writeln('Child.Proc2');
end;

var
  Base: TBase;
begin
  Base := TChild.Create;
  Base.Proc1;
  Writeln;
  Base.Proc2;
  Base.Free;
  Readln;
end.

其输出:

Base.Proc1
Child.Proc1

Base.Proc2

TChild.Proc2 上的警告 声明此方法“将隐藏对同名基础方法的访问”。我看到的是,如果我不重写 Proc2,我就会失去该方法解析其实际类型的能力,而不是其基本类型的能力。如何隐藏对 base 方法的访问?

此外,在关于警告的文档中作为警告的解决方案,指出:

首先,您可以指定覆盖 使派生类的过程也 虚拟的,从而允许继承 要求仍引用原始内容 程序。

现在,如果我从“TChild”(无多态性)创建“TChild”实例,则非重写方法中的继承调用显然引用原始过程。如果我从“TBase”创建“Child”实例,调用甚至不会解析为“TChild”方法,我怎么能调用引用任何内容的“Inherited”呢?

我有什么误解吗?

After having read Ian Boyd's constructor series questions (1, 2, 3, 4), I realize I don't quite grasp the literal meaning on what's being hidden.

I know (correct me if I'm wrong) override's sole purpose is to be able to have polymorphic behavior, so that run-time can resolve a method depending on the actual type of an instance - as opposed to the declared type. Consider the following code:

type
  TBase = class
    procedure Proc1; virtual;
    procedure Proc2; virtual;
  end;

  TChild = class(TBase)
    procedure Proc1; override;
    procedure Proc2;            // <- [DCC Warning]
  end;

procedure TBase.Proc1;
begin
  Writeln('Base.Proc1');
end;
procedure TBase.Proc2;
begin
  Writeln('Base.Proc2');
end;

procedure TChild.Proc1;
begin
  inherited Proc1;
  Writeln('Child.Proc1');
end;
procedure TChild.Proc2;
begin
  inherited Proc2;
  Writeln('Child.Proc2');
end;

var
  Base: TBase;
begin
  Base := TChild.Create;
  Base.Proc1;
  Writeln;
  Base.Proc2;
  Base.Free;
  Readln;
end.

Which outputs:

Base.Proc1
Child.Proc1

Base.Proc2

The warning on TChild.Proc2 states that this method "will hide access to the base's method of the same name". What I see is, if I don't override Proc2 I loose the ability of the method's resolving to its actual type, not of its base type. How's that hiding access to base's method?

Further, down the documentation on the warning as a solution to the warning, it is stated that:

First, you could specify override to
make the derived class' procedure also
virtual, and thus allowing inherited
calls to still reference the original
procedure.

Now, if I create a 'TChild' instance from a 'TChild' (no polymorphism), the inherited call in the non-overridden method clearly refers to the original procedure. If I create the 'Child' instance from a 'TBase', the call does not even resolve to a 'TChild' method, how could I call 'Inherited' that would refer to anything at all?

What am I misunderstanding?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(3

回忆追雨的时光 2024-10-03 14:08:17

除此之外,您将无法定义

TGrandChild = class(TChild) 
  procedure Proc2; override;
end; 

,因为 TGrandChild 看到的 Proc2 是来自 TChild 的非虚拟 Proc2。 TChild.Proc2 对后代隐藏 TBase.Proc2。

编辑:

回答 Sertac 的评论:

var 
  Base: TBase; 
  Child : TChild
begin 
  Child := TChild.Create;
  Base := Child;
  Base.Proc2; 
  Child.Proc2;

  Base.Free; 
  Readln; 

这将输出

Base.Proc2
Base.Proc2
Child.Proc2

所以,似乎两次调用同一方法实际上是调用 2 个不同的方法。这使得代码更难理解(这不实用)并产生意想不到的行为。

Amongs other thing, you won't be able to define

TGrandChild = class(TChild) 
  procedure Proc2; override;
end; 

because Proc2 that TGrandChild sees is the one from TChild that is not virtual. The TChild.Proc2 hide TBase.Proc2 from descendants.

EDIT:

In answer to Sertac's comment:

var 
  Base: TBase; 
  Child : TChild
begin 
  Child := TChild.Create;
  Base := Child;
  Base.Proc2; 
  Child.Proc2;

  Base.Free; 
  Readln; 

That will output

Base.Proc2
Base.Proc2
Child.Proc2

So, what seems to be a call to the same method twice is actually a call to 2 different methods. That makes code harder to understand (which is not practical) and yield unexpected behavior.

谁把谁当真 2024-10-03 14:08:17

你想得太复杂了。隐藏并不意味着您完全无法访问原始内容。它只是意味着(您自己已经注意到了这一点)如果您有一个静态类型 TChild 的对象,并且您在其上调用 Proc2,它会调用 TChild 中的对象,而不是 TBase 中的对象。 Ken说的也是事实。

它警告您,因为原始是虚拟的,隐藏很可能不是人们在编写这样的代码时想要的。至少这是糟糕的编码风格。

You are thinking too complicated. Hiding doesn't mean you completely lose access to the original. It simply means (and you already noted this yourself) if you have an object of static type TChild, and you call Proc2 on it, it calls the one in TChild, and not the one in TBase. Also what Ken said is true.

It is warning you because the original is virtual and hiding is most likely not what people intend when writing code like that. At the very least it's bad coding style.

五里雾 2024-10-03 14:08:17

使用“重新引入”来抑制警告。

Use 'reintroduce' to suppress the warning.

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