Home > Net >  How to override an inherited method from within another inherited class
How to override an inherited method from within another inherited class

Time:10-12

I am wondering if possible to override a method from calling console app or a super super class? I understand I can override WriteLog at DoMath.... however consider that I would like to manage this instead at the console app.

Example:

public class LogThings
{
    public virtual void WriteLog(string value)
    {
        Console.WriteLine("This is the base in LogThings "   value);
    }
}

The class inheriting the base. I kind of thought if I add the method again and mark it with new to implement as a virtual, then I can override this in the console app that inherits DoMath?

public class DoMath : LogThings
{
    public double DoAddition(double a, double b)
    {
        double result;
        result = a   b;
        WriteLog(result.ToString()); // < the operation I need to overload
        return result;
    }

    public new virtual void WriteLog(string value)
    {
        Console.WriteLine("this is overriding the base in DoMath");
        base.WriteLog(value);
    }
}

Some console app using the doMathANdLog class library:

class Program : DoMath
{
    static void Main(string[] args)
    {
        var m = new DoMath();
        m.DoAddition(1, 2);
      
        Console.ReadLine();
    }

    public override void WriteLog(string value)
    {
        Console.WriteLine("this is not overriding.");
    }
}

Result is this when running it:

this is overriding the base in DoMath
This is the base in LogThings 3

Is there a way to do this?

CodePudding user response:

As noted in the comments, DoMath provides a new implementation (it's in the definition there) of the WriteLog method. Your Program class then overrides that implementation.

Where it's 'failing' is here:

var m = new DoMath();

You're not creating an instance of Program with its overridden method, so that override is never used. Try new Program() instead.

CodePudding user response:

That's a simultaneously fun and annoying problem to have! :) I believe that one of the missing links here is this:

  • The override modifier is related to virtual or abstract methods; a method with an override modifier simply provides an alternative implementation to an existing virtual or abstract method. A virtual method has a default implementation, an abstract method has no implementation at all.
  • The new modifier however can be applied to any method and simply allows the reuse of a name that was already taken. These methods are not related to each other at all, the only similarity being that they forcibly share the same name.

The problem with new is that the type using a new method "pretends" that the original implementation never existed. The base class however is absolutely unaware of this - new severs the link in the hierarchy, and this is what's casing your problem.

Generally speaking, you do not want to use the new modifier.

That, and you probably wanted to use var m = new Program(); instead - reasons being explained below.


Consider these two pieces of code:

LogThings a = new DoMath();
a.WriteLog("something");

and

LogThings a = new Program();
a.WriteLog("something");

At this point, the method being called is LogThings.WriteLog(). Even though we instantiate a DoMath or Program class that provides a new method, the LogThings part of the world doesn't "know" that. It instead believes to have a virtual method that doesn't happen to be overridden. As a result, this code prints:

This is the base in LogThings something

As mentioned above: new severs that link.

In the next example, the method being called is indeed DoMath.WriteLog(), because we're now simply instantiating the DoMath() class and call its LogThings method.

DoMath b = new DoMath();
b.WriteLog("something");

Not surprisingly, this code prints

this is overriding the base in DoMath

This is the base in LogThings something

Note that it does not print "this is not overriding" because we did not instantiate an instance of the Program class. Likewise, the base.LogThings() call has nothing to do with "overriding", it simply changes the focus to the LogThings type and calls whatever implementation it knows.

This is similar to the original code you used:

var m = new DoMath();

Lastly, consider this version:

DoMath c = new Program();
c.WriteLog("something");

Here, the Program class actually overrides the virtual void WriteLog method of DoMath. Consequently, this code prints

this is not overriding.

... which is now wrong, because it does.


The key to understanding this is that each class containing virtual or abstract methods has what's called a virtual function table, or vtable. This vtable is "inherited" by derived classes and allows the compiler to know which implementation of a method to call (through a so-called virtual dispatch).

You can consider an entry in the vtable to be something like a pointer to the actual implementation of a method (the one from the current class), followed by a pointer to the previous implementation.

In your example of DoMath and Program, instantiating the DoMath class would produce a vtable consisting of only

DoMath.WriteLog(string) -> null

whereas instantiating the Program class would produce an entry like this:

Program.WriteLog(string) -> DoMath.WriteLog(string) -> null

This is why ((DoMath)new Program()).WriteLog() works - even though we look at a DoMath reference, the compiler looks up the vtable for the instantiated type (Program) and can follow the chain up to the actual implementation (Program.WriteLog).

Do however note the makeshift null in there. Because the DoMath class declares the WriteLog method as new, it is considered to be a - well - new method, which is unrelated to the one from LogThings. For LogThings, the vtable world still looks somewhat like this:

LogThings.WriteLog(string) -> null

Because there is no legit override - just a different method that happens to have the same name - ((LogThings)new Program()).WriteLog() calls LogThings.WriteLog(), as that's the last implementation in the chain. The new essentially "forces in" another vtable, resulting in this somewhat split-brained setup.

Please note that this description of a vtable is drastically oversimplified; there's plenty of good material out there on that topic however.

  • Related