重写与方法隐藏
我对 C# 中的重写和隐藏方法有点困惑。每个的实际用途以及对何时使用每个的解释也将受到赞赏。
我对覆盖感到困惑 - 为什么我们要覆盖?到目前为止我了解到的是,通过覆盖,我们可以为派生类的方法提供所需的实现,而无需更改签名。
如果我不重写超类的方法并且对子类中的方法进行更改,那么是否会对超类方法进行更改?
我也对以下内容感到困惑 - 这表明了什么?
class A
{
virtual m1()
{
console.writeline("Bye to all");
}
}
class B : A
{
override m1()
{
console.writeLine("Hi to all");
}
}
class C
{
A a = new A();
B b = new B();
a = b; (what is this)
a.m1(); // what this will print and why?
b = a; // what happens here?
}
I am a bit confused about overriding vs. hiding a method in C#. Practical uses of each would also be appreciated, as well as an explanation for when one would use each.
I am confused about overriding - why do we override? What I have learnt so far is that by overring we can provide desired implementation to a method of a derived class, without changing the signature.
If I don't override the method of the superclass and I make changes to the method in the sub class, will that make changes to the super class method ?
I am also confused about the following - what does this demonstrate?
class A
{
virtual m1()
{
console.writeline("Bye to all");
}
}
class B : A
{
override m1()
{
console.writeLine("Hi to all");
}
}
class C
{
A a = new A();
B b = new B();
a = b; (what is this)
a.m1(); // what this will print and why?
b = a; // what happens here?
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
考虑一下:
重写是经典的面向对象方式,派生类可以比基类具有更具体的行为(在某些语言中,您别无选择,只能这样做)。当对对象调用虚拟方法时,将调用该方法的最派生版本。因此,即使我们将
isReallyDerived
作为BaseClass
处理,也会使用DerivedClass
中定义的功能。隐藏意味着我们有完全不同的方法。当我们在
isReallyDerived
上调用WriteNum()
时,我们无法知道DerivedClass
上有不同的WriteNum()
code> 所以它没有被调用。仅当我们将对象作为DerivedClass
处理时才能调用它。大多数时候隐藏是不好的。一般来说,如果一个方法可能在派生类中更改,则应该将其设置为虚拟方法,然后在派生类中重写它。然而,它有两个用途:
向前兼容性。如果
DerivedClass
有一个DoStuff()
方法,然后将BaseClass
更改为添加一个DoStuff()
方法,(请记住,它们可能由不同的人编写并存在于不同的程序集中),那么对成员隐藏的禁止将突然使DerivedClass
出现错误,而无需更改。此外,如果BaseClass
上的新DoStuff()
是虚拟的,那么在DerivedClass
上自动对其进行重写可能会导致预编译现有方法在不应该调用的时候被调用。因此,最好将隐藏设置为默认值(我们使用new
来明确表示我们确实要隐藏,但如果不隐藏它,则会隐藏并在编译时发出警告)。穷人的协方差。考虑
BaseClass
上的Clone()
方法,该方法返回一个新的BaseClass
,它是所创建的 BaseClass 的副本。在DerivedClass
的重写中,这将创建一个DerivedClass
但将其作为BaseClass
返回,这没有那么有用。我们可以做的是重写一个虚拟的受保护的CreateClone()
。在BaseClass
中,我们有一个Clone()
,它返回结果 - 一切都很好 - 在DerivedClass
中,我们用一个新的 < code>Clone() 返回一个DerivedClass
。在BaseClass
上调用Clone()
将始终返回一个BaseClass
引用,该引用将是一个BaseClass
值或 < code>DerivedClass 适当的值。对DerivedClass
调用Clone()
将返回一个DerivedClass
值,这正是我们在该上下文中想要的值。此原理还有其他变体,但应该注意的是,它们都非常罕见。对于第二种情况,需要注意的一个重要事项是,我们精确地使用隐藏来消除调用代码的意外,因为使用
DerivedClass
的人可能合理地期望其 < code>Clone() 返回一个DerivedClass
。任何调用方式的结果都保持一致。大多数隐藏的情况都会带来意外的风险,这就是为什么它们通常不受欢迎的原因。正是因为它解决了隐藏经常带来的问题,所以这一点是合理的。总而言之,隐藏有时是必要的,虽然很少有用,但通常是不好的,所以要非常警惕。
Consider:
Overriding is the classic OO way in which a derived class can have more specific behaviour than a base class (in some languages you've no choice but to do so). When a virtual method is called on an object, then the most derived version of the method is called. Hence even though we are dealing with
isReallyDerived
as aBaseClass
then functionality defined inDerivedClass
is used.Hiding means that we have a completely different method. When we call
WriteNum()
onisReallyDerived
then there's no way of knowing that there is a differentWriteNum()
onDerivedClass
so it isn't called. It can only be called when we are dealing with the object as aDerivedClass
.Most of the time hiding is bad. Generally, either you should have a method as virtual if its likely to be changed in a derived class, and override it in the derived class. There are however two things it is useful for:
Forward compatibility. If
DerivedClass
had aDoStuff()
method, and then later onBaseClass
was changed to add aDoStuff()
method, (remember that they may be written by different people and exist in different assemblies) then a ban on member hiding would have suddenly madeDerivedClass
buggy without it changing. Also, if the newDoStuff()
onBaseClass
was virtual, then automatically making that onDerivedClass
an override of it could lead to the pre-existing method being called when it shouldn't. Hence it's good that hiding is the default (we usenew
to make it clear we definitely want to hide, but leaving it out hides and emits a warning on compilation).Poor-man's covariance. Consider a
Clone()
method onBaseClass
that returns a newBaseClass
that's a copy of that created. In the override onDerivedClass
this will create aDerivedClass
but return it as aBaseClass
, which isn't as useful. What we could do is to have a virtual protectedCreateClone()
that is overridden. InBaseClass
we have aClone()
that returns the result of this - and all is well - inDerivedClass
we hide this with a newClone()
that returns aDerivedClass
. CallingClone()
onBaseClass
will always return aBaseClass
reference, which will be aBaseClass
value or aDerivedClass
value as appropriate. CallingClone()
onDerivedClass
will return aDerivedClass
value, which is what we'd want in that context. There are other variants of this principle, however it should be noted that they are all pretty rare.An important thing to note with the second case, is that we've used hiding precisely to remove surprises to the calling code, as the person using
DerivedClass
might reasonably expect itsClone()
to return aDerivedClass
. The results of any of the ways it could be called are kept consistent with each other. Most cases of hiding risk introducing surprises, which is why they are generally frowned upon. This one is justified precisely because it solves the very problem that hiding often introduces.In all, hiding is sometimes necessary, infrequently useful, but generally bad, so be very wary of it.
重写是指您在子类中提供方法的新
重写
实现,而该方法在基类中定义为虚拟
。隐藏是指您在子类中提供方法的新实现,而该方法未在基类中定义为
虚拟
,或者您的新实现未指定覆盖
。隐藏往往是不好的;如果可以避免的话,通常应该尽量不这样做。隐藏可能会导致意外的事情发生,因为隐藏方法仅在您定义的实际类型的变量上调用时使用,而不是在使用基类引用时使用......另一方面,被重写的虚拟方法最终将是调用正确的方法版本,即使使用子类上的基类引用进行调用也是如此。
例如,考虑这些类:
让我们在匹配的引用中使用 InheritedClass 的实例这样调用它
:这两种方法都表示它们正在运行 InheritedClass 版本。
此代码创建相同 InheritedClass 的实例,但将其存储在 BaseClass 引用中:
通常,根据 OOP 原则,您应该期望得到与上面示例相同的输出。但你没有得到相同的输出:
当您编写 InheritedClass 代码时,您可能希望对
Method2()
的所有调用都运行您在其中编写的代码。通常,这就是它的工作方式 - 假设您正在使用已重写的虚拟方法。但由于您使用的是new
/hidden 方法,因此它会调用您正在使用的引用上的版本。如果这是您真正想要的行为,那么;就这样吧。但我强烈建议,如果这就是您想要的,那么代码可能存在更大的架构问题。
Overriding is when you provide a new
override
implementation of a method in a descendant class when that method is defined in the base class asvirtual
.Hiding is when you provide a new implementation of a method in a descendant class when that method is not defined in the base class as
virtual
, or when your new implementation does not specifyoverride
.Hiding is very often bad; you should generally try not to do it if you can avoid it at all. Hiding can cause unexpected things to happen, because Hidden methods are only used when called on a variable of the actual type you defined, not if using a base class reference... on the other hand, Virtual methods which are overridden will end up with the proper method version being called, even when called using the base class reference on a child class.
For instance, consider these classes:
Let's call it like this, with an instance of InheritedClass, in a matching reference:
This returns what you should expect; both methods say they are running the InheritedClass versions.
This code creates an instance of the same, InheritedClass, but stores it in a BaseClass reference:
Normally, under OOP principles, you should expect the same output as the above example. But you don't get the same output:
When you wrote the InheritedClass code, you may have wanted all calls to
Method2()
to run the code you wrote in it. Normally, this would be how it works - assuming you are working with avirtual
method that you have overridden. But because you are using anew
/hidden method, it calls the version on the reference you are using, instead.If that's the behavior you truly want, then; there you go. But I would strongly suggest that if that's what you want, there may be a larger architectural issue with the code.
方法重写是简单地重写派生类中基类方法的默认实现。
方法隐藏:您可以在派生类中的虚拟方法之前使用“new”关键字,
就像
现在如果您创建另一个从 Bar 派生的类 Bar1 一样,您可以覆盖 Bar 中定义的 foo1 。
Method Overriding is simpley override a default implementation of a base class method in the derived class.
Method Hiding : You can make use of 'new' keyword before a virtual method in a derived class
as
now if you make another class Bar1 which is derived from Bar , you can override foo1 which is defind in Bar.