Given
public class Animal
{
public Animal()
{
Console.WriteLine("Animal constructor called");
}
public virtual void Speak()
{
Console.WriteLine("animal speaks");
}
}
public class Dog: Animal
{
public Dog()
{
Console.WriteLine("Dog constructor called");
this.Speak();
}
public override void Speak()
{
Console.WriteLine("dog speaks");
base.Speak();
}
}
this.Speak() calls Dog.Speak(). Remove Speak() from dog and suddenly this.Speak() calls Animal.Speak(). Why does this behave this way? In other words, why does this mean base or this?
To me, an explicit call to base.Speak() makes more sense. Especially when speak is not virtual, surprisingly Speak() is still called when virtual is removed. I understand IS-A relationships from an OO sense, but I can’t wrap my head around this specific problem in C#. This gets especially annoying when people write God class UI’s (practically every business does). I’m looking for “Speak()” inside “this” when I should be looking at “base”.
Subclases automatically inherit behavior from their base classes. If you don’t do anything other than inherit
DogfromAnimalthenthis.Speak()andbase.Speak()both reference the version ofSpeak()that was implemented inAnimal.Where special things start happening is if
DogoverridesSpeak(). This is not possible unlessSpeak()isvirtual. (Thevirtualkeyword doesn’t control inheritance, it controlls overriding.)Only when
DogoverridesSpeak()doesbase.Speak()do something special: In that case, callingSpeak()(orthis.Speak()) will executeDog‘s implementation, because itoverridesAnimal‘s implementation. This is wherebasebecomes useful: it allows you to get around this behavior by specifying that you want to execute the base class’s implementation rather than the override.A common use of this style is in constructors. For example:
In this example,
NamedAnimaldoesn’t have access to the_namefield, but it is still able to set it indirectly by calling the base class’s constructor. But the base class’s signature is the same as one in the base class, so it has to be specified usingbase.With non-constructors it’s also useful to get at behavior that’s not otherwise accessible. For example, if
Animal.Speakwere virtual then we could use an override to tack behavior onto it rather than simply replacing it: