#769 – Pattern – Call a Base Class Method When You Override It

You can call a method in a class’ base class using the base keyword. You can do this from anywhere within the child class, but  it’s a common pattern to call the base class method when you override it.  This allows you to extend the behavior of that method.

Here’s an example.

    public class Dog
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public Dog(string name, int age)
        {
            Name = name;
            Age = age;
        }

        public virtual void DumpInfo()
        {
            Console.WriteLine(string.Format("Dog {0} is {1} years old", Name, Age));
        }
    }

    public class Terrier : Dog
    {
        public double GrowlFactor { get; set; }

        public Terrier(string name, int age, double growlFactor)
            : base(name, age)
        {
            GrowlFactor = growlFactor;
        }

        public override void DumpInfo()
        {
            base.DumpInfo();

            Console.WriteLine(string.Format("  GrowlFactor is {0}", GrowlFactor));
        }
    }

 

            Terrier t = new Terrier("Jack", 17, 9.9);
            t.DumpInfo();

769-001

#684 – Hidden Base Class Members Aren’t Really Hidden

When authoring a derived class, you can hide a member of the base class using the new keyword.  For a method, this indicates that the method in your derived class replaces the method in the base class and will be called when invoked on objects of the derived type.  (It also means that the method will not behave polymorphically).

    public class Dog
    {
        public virtual void Bark()
        {
            Console.WriteLine("Dog: Woof");
        }
    }

    public class Terrier : Dog
    {
        public new void Bark()
        {
            Console.WriteLine("Terrier: Yip yip");
        }
    }

However, if you have an instance of the derived class and cast it to the type of its base class, you’ll end up accessing the method in the base class after all.

            Terrier t = new Terrier();

            t.Bark();         // Yip yip

            ((Dog)t).Bark();  // Woof

#683 – Two Ways an Object Can Behave Polymorphically

There are a couple of different ways that an object can behave polymorphically.  Here are two examples.

Polymorphic behavior #1 – access instance of subclass using reference to base class.

    public class Dog
    {
        public virtual void Bark()
        {
            Console.WriteLine("Dog: Woof");
        }
    }

    public class Terrier : Dog
    {
        public override void Bark()
        {
            Console.WriteLine("Terrier: Yip yip");
        }
    }
            // Terrier method called through Dog reference
            Dog d = new Terrier();
            d.Bark();

Polymorphic behavior #2 – Base class calls method that is overridden in derived class

        // Dog.GuardUs
        public void GuardUs()
        {
            Bark();
        }
            Terrier t = new Terrier();
            t.GuardUs();

#682 – The Real Reason for the new Keyword

Here’s a scenario that illustrates the main reason for the new keyword, allowing a method to not behave polymorphically.

Suppose you use a third-party library that defines a Dog class and you create a Terrier class in your own code that derives from Dog and defines a Speak method.  (Dog does not have a Speak method).

Now let’s say you get a new version of the Dog library in which they’ve added their own Speak method, which is virtual and which they call from the Dog constructor.

Now, when you construct a Terrier object, the Dog constructor will call Speak.  But by default, it’s Dog.Speak that’s called, rather than Terrier.Speak.  The compiler won’t just automatically make Speak behave polymorphically.

When you re-compile your code, you’ll get a warning indicating that you should make your intent explicit, by either marking Terrier.Speak as new (non-polymorphic) or as override (polymorphic).

#680 – Virtual Modifier Combinations

Below is a chart showing all of the possible combinations for the virtual, override, new and sealed modifiers, which dictate polymorphic behavior of inherited members.

The chart shows the allowed combinations for an inheritance tree consisting of three classes–DogTerrier (which inherits from Dog) and Yorkshire (which inherits from Terrier).  It’s assumed that there is a member in each class, e.g. a Bark method.  This chart then shows all the possible combinations of modifiers for that member, within each of the three classes.

For example, you could:

  • Declare Dog.Bark as virtual
  • Declare Terrier.Bark as override
  • Declare Yorkshire.Bark as new

#679 – Hide An Inherited Method with A Virtual Method

You typically hide an inherited method using the new keyword, indicating that the method should not behave polymorphically.  If you later inherit this method in a subclass, you won’t be able to override the method marked as new.

For example:

  • virtual Dog.Bark  – can override
  • new Terrier.Bark – hides Dog.Bark
  • new Yorkshire.Bark – must hide, can’t override

However, if you want to hide an inherited method, but still allow overriding in a subclass, you can use the virtual new combination:

  • virtual Dog.Bark – can override
  • virtual new Terrier.Bark – hides Dog.Bark, but allows overriding
  • override Yorkshire.Bark – overrides Terrier.Bark

In this case, Terrier and Yorkshire objects referenced by variables of type Dog will not behave polymorphically.  But a Yorkshire object referenced by a Terrier variable will behave polymorphically.

 

#677 – Method Marked with new Modifier Cannot Be Overridden

You can use the new modifier on a method to indicate that the method should hide a method of the same name in a base class.  In other words, the method does not behave polymorphically.

If you’ve marked a method as new in a class, that method is not virtual and can not be overridden in a derived class.

In the example below, the Dog class marks Bark as virtual, indicating that it can be overridden.  The Terrier class marks Bark as new, indicating that it does not override Dog.Bark–and that it cannot be overridden.  JRT can therefore not override Bark.

    public class Dog
    {
        public virtual void Bark()
        {
            Console.WriteLine("  Dog.Bark");
        }
    }

    public class Terrier : Dog
    {
        public new void Bark()
        {
            Console.WriteLine("  Terrier is barking");
        }
    }

    public class JRT : Terrier
    {
        public new void Bark()
        {
            Console.WriteLine("  JRT is barking");
        }
    }

#675 – Polymorphic Behavior Requires virtual / override Combination

Recall that polymorphism means that the type of an object at run-time is used to decide what method to call, rather than the static type of the variable that references that object.

In C#, a method behaves polymorphically if and only if the method in the base class is defined as virtual and the method in the derived class is defined as override.  

For example, if Terrier inherits from Dog, we can declare a Dog.Bark method as virtual and a Terrier.Bark method as override.  We then get polymorphic behavior:

Terrier t = new Terrier("Jack");
Dog d = t;

// Polymorphic behavior =
//   Terrier's implementation of Bark is called,
//   because type of object referenced by d is
//   determined at runtime.
d.Bark();

#671 – A Base Class Constructor Can Call a Virtual Method

If a base class constructor calls a virtual method that is overridden in a derived class, the version of the method in the derived class is the one that will get called.

For example, assume that we have a Dog class that defines a virtual Bark method and a Terrier subclass that overrides the Bark method.

    public class Dog
    {
        public Dog()
        {
            Console.WriteLine("Dog constructor");
            Bark();
        }

        public virtual void Bark()
        {
            Console.WriteLine("Woof");
        }
    }

    public class Terrier : Dog
    {
        public Terrier()
            : base()
        {
            Console.WriteLine("Terrier constructor");
        }

        public override void Bark()
        {
            Console.WriteLine("Terrier barking!");
        }
    }

Assume you create an instance of a Terrier.

            Terrier t = new Terrier();

The Terrier constructor calls the Dog constructor, which invokes the Bark method.  But it’s the Bark method in Terrier that is called, rather than the Bark method in Dog.

#616 – Base Class Needs to Know If Polymorphism Is Desired

Let’s say that you design a Dog class that contains a Bark method and that you don’t do anything special to design for inheritance.

    public class Dog
    {
        public void Bark()
        {
            Console.WriteLine("Woof");
        }
    }

Now let’s say that you define several classes that inherit from Dog and provide their own implementation for the Bark method.  Because Dog.Bark was not marked as virtual, they must use the new keyword.

    public class Terrier : Dog
    {
        public new void Bark()
        {
            Console.WriteLine("Terrier says Grrrr");
        }
    }

But now you do not get polymorphic behavior when treating instances of Terrier as instances of Dog.

        static void Main()
        {
            Terrier t = new Terrier();
            t.Bark();  // Terrier.Bark
            SomeoneBark(t);
        }

        static void SomeoneBark(Dog d)
        {
            d.Bark();  // Dog.Bark always invoked--no polymorphism
        }

To achieve polymorphism, you must design for it in the base class by marking a method as virtual.