0

When this code runs the output is "Child running" even though I am casting it to the Parent class? Im probably doing it wrong, if so, how can i achieve the desired result of having an output of "Parent running"? The Parent instance = new Child(); has to remain like that.

class Program
{
    class Parent
    {
        public virtual void Run()
        {
            Console.WriteLine("Parent running.");
        }
    }

    class Child : Parent
    {
        public override void Run()
        {
            Console.WriteLine("Child running.");
        }
    }

    static void Main(string[] args)
    {
        Parent instance = new Child();

        (instance as Parent).Run();

        Console.ReadLine();
    }
}

EDIT:

Noticed if I remove the virtual keyword from the Parent class and mark the Child's version of this method as new it "solves" the issue.

class Program
{
    class Parent
    {
        public void Run()
        {
            Console.WriteLine("Parent running.");
        }
    }

    class Child : Parent
    {
        public new void Run()
        {
            Console.WriteLine("Child running.");
        }
    }

    static void Main(string[] args)
    {
        Parent instance = new Child();

        (instance as Parent).Run();

        Console.ReadLine();
    }
}
Joao Vitor
  • 169
  • 1
  • 9
  • 4
    That's how a `virtual` method works and that is almost always the desired behavior. If you don't want it to be virtual, you can try leaving off the `virtual` keyword, but that's typically a code smell. – JLRishe Jan 09 '20 at 15:21
  • 3
    Casting an object doesn't change the type of the object, your instance is still a `Child`, so the implementation on child will be run. – Jonathon Chase Jan 09 '20 at 15:22
  • @JonathonChase Not completely true. As JL said, if the virtual keyword is omitted, virtual table wont be created and it will use the parent implementation. – Divisadero Jan 09 '20 at 15:23
  • Check [this out](https://stackoverflow.com/questions/3747711/call-base-function-then-inherited-function). I could have even closed your question as a duplicate of that one. – Wiktor Zychla Jan 09 '20 at 15:28
  • @Divisadero Yes, you can slot a new method instead of overriding a virtual one, but the instance will still be typed as `Child` despite the cast. – Jonathon Chase Jan 09 '20 at 15:30
  • Sure, that part was correct – Divisadero Jan 09 '20 at 20:10

2 Answers2

2

You basically can't (short of using tricks with reflection). That's how inheritance in C# works.

What you could do instead of overriding Run is to shadow it:

public class Parent
{
    public void Run() => Console.WriteLine("Parent");
}

public class Child : Parent
{
    public new void Run() => Console.WriteLine("Child");
}

var child = new Child();
child.Run(); // prints "Child"
((Parent)child).Run(); // prints "Parent"

Shadowing is rarely a good idea as it can be confusing when an object changes its behaviour depending on the type of its variable. For more on shadowing, have a look at e. g. this question.

germi
  • 4,628
  • 1
  • 21
  • 38
  • FYI I believe the accepted terminology (at least what MSDN uses) is "method hiding" and not "method shadowing". – juharr Jan 09 '20 at 16:36
-1
virtual method should not do anything,it's just a contract,what your goal is a bad ideal.

you should do it like this:

public class animal
{
   public virtual void eat()
   {
      //don't do anything
   }
}

public class dog:animal
{
   public override void eat()
   {
     //eat Meat
   }
}

public class sheep:animal
{
   public override void eat()
   {
     //eat grass
   }
}
zhouxu
  • 1
  • "Virtual methods should not do anything"? Yes they do; they provide a default implementation, that may or may not be overridden in a subclass. – Johnathan Barclay Jan 09 '20 at 15:38