- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我收到了有关方法“Create”隐藏基类虚拟方法的 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? ):
What is meant by hiding is that from the derived class you no longer have access to the virtual method declared in the base class. You cannot refer to it since it has the same name as the method declared in the derived class. And that latter method is the one that is visible from the derived class.
但我有点困惑,因为似乎祖先方法并没有真正隐藏,因为派生类总是可以使用 inherited
关键字来调用基类中的方法。那么“隐藏”真的意味着“有点隐藏”吗?
我想我也明白使用保留字override
将防止编译器警告,但过程签名必须相同(即没有新添加的参数)。我不能在这里使用它。
我不明白的是为什么隐藏是值得警告的事情。在上面的代码示例中,我不希望 TMachine.Assign()
的用户以某种方式使用 TMachine.Assign()
。在我的扩展类(class)中,我有扩展的需求,因此希望他们使用新的和改进的功能。所以看来隐藏旧代码正是我想要的。我对虚拟方法的理解是,根据运行时对象的实际类型调用正确的方法。我认为这对本案没有任何影响。
其他代码,将添加到上面的示例代码中
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警告]Unit1.pas(27): W1010方法“Create”隐藏基类型“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? ) 中写道,多态性是:“面向对象编程的概念。不同对象以各自的方式响应相同消息的能力称为多态性。” 那么我是否呈现了一个不同的界面,即不再是相同的消息,从而破坏了多态性?
我错过了什么?总之,在我的示例中隐藏基本代码不是一件好事吗?
最佳答案
这里的危险是您可能会对基类引用调用Assign
。因为您没有使用override
,所以不会调用您的派生类方法。这样你就颠覆了多态性。
根据最小惊喜原则,您应该在此处使用override
,或者为您的派生类方法指定一个不同的名称。后一个选项很简单。前者看起来像这样:
type
TMachine = class(TPersistent)
public
Horsepower : integer;
procedure Assign(Source : TPersistent); override;
end;
...
procedure TMachine.Assign(Source : TPersistent);
begin
if Source is TMachine then begin
Horsepower := TMachine(Source).Horsepower;
end else begin
inherited Assign(Source);
end;
end;
这允许您的类与TPercient
的多态设计合作。如果不使用override
,这是不可能的。
您的下一个示例与虚拟构造函数类似。将构造函数设为虚拟的全部意义在于,您可以在运行时之前不知道实例的类型的情况下创建实例。典型的示例是流框架,该框架处理 .dfm/.fmx 文件并创建对象并设置其属性。
该流框架依赖于 TComponent
的虚拟构造函数:
constructor Create(AOwner: TComponent); virtual;
如果您希望组件与流框架一起使用,则必须重写此构造函数。如果你隐藏它,那么流框架就找不到你的构造函数。
考虑流框架如何实例化组件。它不知道它需要使用的所有组件类。例如,它不能考虑第三方代码,即您编写的代码。 Delphi RTL 无法了解其中定义的类型。流框架实例化如下组件:
type
TComponentClass = class of TComponent;
var
ClassName: string;
ClassType: TComponentClass;
NewComponent: TComponent;
....
ClassName := ...; // read class name from .dfm/.fmx file
ClassType := GetClass(ClassName); // a reference to the class to be instantiated
NewComponent := ClassType.Create(...); // instantiate the component
ClassType
变量保存一个元类。这使我们能够表示直到运行时才知道的类型。我们需要以多态方式分派(dispatch)对 Create
的调用,以便执行组件构造函数中的代码。除非您在声明该构造函数时使用override
,否则不会。
确实,所有这些都可以归结为多态性。如果您对多态性的理解不牢固,正如您所建议的,那么您将很难理解其中的任何一个。我认为您的下一步行动是更好地理解多态性是什么。
关于oop - 隐藏基类的虚方法有什么问题?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44210938/
关闭。这个问题是opinion-based .它目前不接受答案。 想改善这个问题吗?更新问题,以便可以通过 editing this post 用事实和引文回答问题. 4年前关闭。 Improve t
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
在面向对象的编程中,“基类”是派生其他类的类(http://en.wikipedia.org/wiki/Base_class)。 但是,基类的反面是什么?换句话说,什么是没有任何子类的类? 编辑:我正
关闭。这个问题需要更多focused .它目前不接受答案。 想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post . 8年前关闭。 Improve this questi
据我了解,OOP 是大型项目最常用的范式。我也知道大系统的一些较小的子集使用其他范式(例如 SQL,它是声明性的),并且我也意识到在较低级别的计算 OOP 并不真正可行。但在我看来,通常更高级别的解决
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
最近听说OOP(Java)有9条规则。我只知道四种:抽象、多态、继承和封装。 OOP 还有更多规则吗? 最佳答案 看来您正在寻找的是 Principles of Object-Oriented Des
我曾经在一次采访中被问到“OOP 的 3 个主要概念是什么?”。我回答说,我认为有4个,如下: 继承 封装 抽象 多态性 我说得对吗? 最佳答案 语言要成为面向对象有3个要求: 仅支持封装(对象)的语
我有一个关于特定 OOP 问题的组织的简单问题。 假设我有一个地形类,里面充满了瓷砖。 Tile 类有多个派生类,即 Door。 Door 类有一个名为 open() 的方法,用于打开门,还有一个名为
就目前情况而言,这个问题不太适合我们的问答形式。我们希望答案得到事实、引用资料或专业知识的支持,但这个问题可能会引发辩论、争论、民意调查或扩展讨论。如果您觉得这个问题可以改进并可能重新开放,visit
我是 Go 的新手,然后我通过示例搜索了很多如何拥有带有静态函数/变量的静态类,例如 C#。但是,我找不到任何可以很好地回答它的东西。也许这个问题看起来很愚蠢,但我不喜欢不确定或不完全理解某事。 假设
我曾尝试搜索此问题的答案,但很难用语言表达,而且许多问题要么是关于如何创建类,要么是关于如何做非常具体的事情。我需要更多的实用概述 - 我是自学成才的,我了解对象是什么(以及如何创建它们),但我从未见
在开始编码之前,我通常会尝试在没有太多分析(没有图表)的情况下进行 TDD。通常我发现自己将一个类拆分为其他类以分离关注点。我想知道更深入的分析是否会阻止这种情况。我认为大部分面向对象分析无法预测其中
在阅读单例时,我发现这个解释是使用单例的原因: since these object methods are not changing the internal class state, we can
如这里所述 https://standardofnorms.wordpress.com/2012/09/02/4-pillars-of-object-oriented-programming/ 并作为
我是这个网站的新手,所以如果我在发布问题时做错了什么,请告诉我,以便我下次修复。 我很好奇从单个基类继承多个类是否是糟糕的 OOP 实践。这可能不太合理,所以我要详细说明一下。 例如,假设您正在设计一
我对“工厂相关”设计模式及其 OOP 实现的理解一直很简单。 一个 《工厂法》是类内部的一个方法,它有一个接口(interface)(或抽象类)作为返回类型,并根据一些内部逻辑构造实现该接口(inte
C# 中的“密封”关键字,Java 中的 Final。 因为我几乎从不创建任何图表并且我只使用已经完成的类(来自框架)我多年后仍然不知道为什么有人会“锁定”一个类所以它永远不会被扩展/继承。 它是有益
我正在研究面向对象的概念,抽象概念基本上被描述为对用户隐藏实现。因此,如果类中有一个成员函数并且我们为某些任务调用该函数,抽象表示用户不应该关心事情是如何完成的,而应该只知道正在完成什么。但即使在非面
我是一名优秀的程序员,十分优秀!