【发布时间】:2017-10-27 21:36:32
【问题描述】:
我收到关于Method 'Create' hides virtual method of base. 的 Delphi 编译器警告
我查看了几个 Stack Overflow 链接(见下文),但我不明白这个警告背后的逻辑,以及为什么它被认为是不好的编码实践。我希望其他人可以帮助我理解
我将包含一些示例代码:
type
TMachine = class(TPersistent)
private
public
Horsepower : integer;
procedure Assign(Source : TMachine);
end;
...
procedure TMachine.Assign(Source : TMachine);
begin
inherited Assign(Source);
Self.Horsepower := Source.HorsePower;
end;
这会导致编译器警告。
[dcc32 Warning] Unit1.pas(21): W1010 Method 'Assign' hides virtual method of base type 'TPersistent'
我一直忽略此警告,因为它对我没有任何意义。但这以另一种方式给我带来了麻烦(请参阅我的其他帖子:Why does Delphi call incorrect constructor during dynamic object creation?),所以我决定尝试更好地理解这一点。
我知道如果我使用保留字reintroduce,错误就会消失,但我看到它反复发布,这是一个坏主意。正如 Warren P 在这里 (Delphi: Method 'Create' hides virtual method of base - but it's right there) 所写,“恕我直言,如果你需要重新引入,你的代码闻起来很糟糕”。
我想我明白“隐藏”是什么意思。正如 David Heffernan 在这里所说的 (What causes "W1010 Method '%s' hides virtual method of base type '%s'" warning?):
隐藏的意思是从派生类中你不再可以访问基类中声明的虚方法。您不能引用它,因为它与派生类中声明的方法同名。后一种方法是从派生类中可见的方法。
但我有点困惑,因为似乎祖先方法并没有真正隐藏,因为派生类总是可以只使用inherited关键字来调用基类中的方法。那么“隐藏”真的意味着“有点隐藏”吗?
我想我也明白使用保留字override 会阻止编译器警告,但过程签名必须相同(即没有新添加的参数)。我不能在这里使用它。
我不明白为什么隐藏是需要警告的事情。在上面的代码示例中,我不希望TMachine.Assign() 的用户以某种方式使用TPersistent.Assign()。在我的扩展类中,我有扩展的需求,因此希望他们使用新的和改进的功能。所以似乎隐藏旧代码正是我想要的。我对virtual 方法的理解是在运行时根据对象的实际类型调用正确的方法。我认为在这种情况下应该没有任何影响。
附加代码,将添加到上面的示例代码中
TAutomobile = class(TMachine)
public
NumOfDoors : integer;
constructor Create(NumOfDoors, AHorsepower : integer);
end;
...
constructor TAutomobile.Create(ANumOfDoors, AHorsepower : integer);
begin
Inherited Create(AHorsepower);
NumOfDoors := ANumOfDoors;
end;
这会添加新的编译器警告消息:[dcc32 Warning] Unit1.pas(27): W1010 Method 'Create' hides virtual method of base type 'TMachine'
我尤其不明白使用带有附加参数的新构造函数会出现的问题。在这篇文章 (SerialForms.pas(17): W1010 Method 'Create' hides virtual method of base type 'TComponent') 中,智慧似乎是应该引入一个具有不同名称的构造函数,例如CreateWithSize。这似乎允许用户选择他们想要使用的构造函数。
如果他们选择旧的构造函数,扩展类可能会丢失一些创建所需的信息。但是,如果相反,我“隐藏”了先前的构造函数,那么它在某种程度上是糟糕的编程。 Marjan Venema 在同一个链接中写了关于reintroduce 的文章:Reintroduce 打破了多态性。这意味着您不能再使用元类(TxxxClass = Tyyy 的类)来实例化您的 TComponent 后代,因为它的 Create 不会被调用。我完全不明白这一点。
也许我需要更好地理解多态性。 Tony Stark 在此链接 (What is polymorphism, what is it for, and how is it used?) 中写道,多态性是:“面向对象编程的概念。不同对象以自己的方式响应相同消息的能力称为多态性。” em> 那么我是不是呈现了一个不同的界面,即不再是一个相同的消息,从而破坏了多态性?
我错过了什么?总之,在我的示例中隐藏基本代码不是一件好事吗?
【问题讨论】:
-
长话短说,它只是确保您知道自己在做什么。如果这样做,您可以通过在末尾添加
reintroduce;来隐藏它以隐藏警告。我个人不明白为什么有人说reintroduce是不好的做法,我在 RTL 本身中看到过。 -
@Jerry:在 VCL/RTL 中看到它并不意味着它是好的代码或实践。 Delphi 源代码中有大量错误代码。
-
@Ken 我同意这一点。我仍然没有看到使用
reintroduce的危害,但在某些情况下我别无选择 - 当我确实需要以不同的方式实现某些东西时。在某些构造函数中尤其如此。 -
@Jerry:我没有说使用
reintroduce有什么问题。我只是指出 我在 RTL 本身中看到过 没有意义。 :-) -
@Jerry 你对 TThread 大错特错。它的构造函数不是虚拟的。
标签: oop delphi inheritance polymorphism