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?
}
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
isReallyDerivedas aBaseClassthen functionality defined inDerivedClassis used.Hiding means that we have a completely different method. When we call
WriteNum()onisReallyDerivedthen there’s no way of knowing that there is a differentWriteNum()onDerivedClassso 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
DerivedClasshad aDoStuff()method, and then later onBaseClasswas 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 madeDerivedClassbuggy without it changing. Also, if the newDoStuff()onBaseClasswas virtual, then automatically making that onDerivedClassan 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 usenewto 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 onBaseClassthat returns a newBaseClassthat’s a copy of that created. In the override onDerivedClassthis will create aDerivedClassbut return it as aBaseClass, which isn’t as useful. What we could do is to have a virtual protectedCreateClone()that is overridden. InBaseClasswe have aClone()that returns the result of this – and all is well – inDerivedClasswe hide this with a newClone()that returns aDerivedClass. CallingClone()onBaseClasswill always return aBaseClassreference, which will be aBaseClassvalue or aDerivedClassvalue as appropriate. CallingClone()onDerivedClasswill return aDerivedClassvalue, 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
DerivedClassmight 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.