“方法'%s'隐藏基类型'%s'的虚拟方法”。真正被隐藏的是什么?

时间:2010-10-07 04:04:37

标签: delphi override

在阅读Ian Boyd的构造函数系列问题(1234)之后,我意识到我并不完全掌握关于被隐藏的内容的字面含义。

我知道(如果我错了,请纠正我)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 states that此方法“将隐藏对基本同名方法的访问”。我所看到的是,如果我不覆盖Proc2,我就失去了方法解析其实际类型的能力,而不是其基本类型。如何隐藏对base方法的访问?

此外,关于警告的文档作为警告的解决方案,声明:

  

首先,您可以指定覆盖到   制作派生类的程序   虚拟,从而允许继承   打电话仍然参考原件   过程

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

我误解了什么?

3 个答案:

答案 0 :(得分:5)

Amongs其他的东西,你将无法定义

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

因为TGrandChild看到的Proc2是来自TChild的非虚拟的。来自后代的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种不同方法的调用。这使得代码更难理解(这不是实用)并产生意外行为。

答案 1 :(得分:2)

你的想法太复杂了。隐藏并不意味着你完全无法访问原始版本。它只是意味着(你自己已经注意到了)如果你有一个静态类型TChild的对象,你在它上面调用Proc2,它会调用TChild中的那个,而不是TBase中的那个。肯也说的是真的。

它警告你,因为原件是虚拟的,并且隐藏很可能不是人们在编写这样的代码时想要的。至少它的编码风格很差。

答案 2 :(得分:2)

使用'重新引入'来禁止警告。