1

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?

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
8six7
  • 23
  • 2
  • 4
    Why are you claiming the method in `DoMath` is overriding the base method when it is not overriding it, and instead making a new method? If you want to override it *actually `override` it*. – Servy Oct 11 '21 at 20:15
  • 2
    You are creating an instance of `DoMath` and not an instance of `Program`. But even if you would create an instance of Program, DoMath redefines the method WriteLog instead of overriding it. – Steeeve Oct 11 '21 at 20:27
  • 1
    *I kind of thought if I add the method again and mark it with new to implement as a virtual* - run that by me again? – Caius Jard Oct 11 '21 at 21:15
  • Very confusing what you want and how you trying to achieve that... https://stackoverflow.com/questions/392721/difference-between-shadowing-and-overriding-in-c is probably good read for you to [edit] question to clarify what you want to achieve and what you need to be explained. – Alexei Levenkov Oct 11 '21 at 21:21

2 Answers2

0

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.

Corey
  • 15,524
  • 2
  • 35
  • 68
0

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.

sunside
  • 8,069
  • 9
  • 51
  • 74
  • 1
    Thank you!. This was an excellent review of the question. I think things went off on another branch with the deep dive on the 'new' keyword and my misuse of it. Still very thorough answer. Thanks for taking the time to write it out. – 8six7 Oct 12 '21 at 00:18