19

I have the following code.

public class Parent
{
    public void Print()
    {
        Console.WriteLine ("Parent Method");
    }
}

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

public class Program
{
    public static void Main()
    {
        Child C = new Child();
        C.Print();
    }
}

If I run this code, I get the result "Child Method" But if I do the following, why do I get the result "Parent Method"?

public class Parent
{
    public void Print()
    {
        Console.WriteLine ("Parent Method");
    }
}

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

public class Program
{
    public static void Main()
    {
        Parent P = new Child();   // The only difference is this.
        P.Print();
    }
}

The only difference is as below

Child C = new Child();   
Parent P = new Child();

I thought new Child() means that we create the instance of Child class. And I thought both, C and P, are just object reference variables that hold the location of instance of Child class.
Can you correct me if I'm wrong or tell me if I miss something because I don't understand why in the above cases I get different results?

ZygD
  • 22,092
  • 39
  • 79
  • 102
JCronin
  • 215
  • 1
  • 2
  • 6
  • 3
    Because you are hiding methods, not overriding them. When you write P.Print, the compiler can only call the parents print method, not the hidden child method. – Ron Beyer Jul 28 '15 at 18:49
  • Possible duplicate: http://stackoverflow.com/questions/17717570/why-does-calling-a-method-in-my-derived-class-call-the-base-class-method – Fernando Matsumoto Jul 28 '15 at 18:49
  • As an aside, I recommend avoiding method hiding unless you legitimately need it. It tends to make code harder to maintain. Quoting Eric Lippert's [Method Hiding Apologia](http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx), "It lets derived types appear to break the contracts of base types. If a derived type D hides a method M on base class B because D.M does something different than B.M, shouldn't it have a different name?" – Brian Jul 29 '15 at 13:17

5 Answers5

21

It's because you've redeclared the Print method in Child. So at compile time, P.Print() resolves to Parent.Print, but C.Print() resolves to Child.Print(). If you had a virtual method which was overridden in Child instead, they'd both print "Child Method":

public class Parent
{
    // Declare this as virtual, allowing it to be overridden in
    // derived classes. The implementation will depend on the
    // execution-time type of the object it's called on.
    public virtual void Print()
    {
        Console.WriteLine ("Parent Method");
    }
}

public class Child : Parent
{
    // Override Parent.Print, so if Print is called on a reference
    // with compile-time type of Parent, but at execution it
    // refers to a Child, this implementation will be executed.
    public override void Print()
    {
        Console.WriteLine ("Child Method");
    }
}

Related:

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
10

Here is what happens under the hood

Child C = new Child();
C.Print();

Because you are hiding methods, not overriding them. so Print method in Parent is hidden and Child.Print() is invoked.

enter image description here

 Parent P = new Child();   // The only difference is this.
 P.Print();

This (New Child()) will be called on a Parent type Reference.

enter image description here

if you try this one, Parent type reference will be casted to Child type. Henceforth Child.Print() is invoked.

Parent P = new Child(); 
((Child)P).Print();

enter image description here

output will be: Child Method

yantaq
  • 3,968
  • 2
  • 33
  • 34
  • Thank you for the answer but could you tell me what they are?? – JCronin Jul 28 '15 at 19:16
  • @JCronin they are CIL. CIL is a low level language. basically when you compile your code, it will be compiled into intermediate language (IL) it is also called MSIL ( Microsoft Intermediate Language). you can see IL code using https://msdn.microsoft.com/en-us/library/f7dy01k1(v=vs.110).aspx BTW, I used LINQPad to get the IL code. you can check it here https://www.linqpad.net/ – yantaq Jul 28 '15 at 19:23
5

Since the Print method is not virtual, the compiler will not emit code to tell the CLR to invoke the method according to the actual runtime type.

So, when your variable is referred as Child, Child.Print would be invoked. But, when you're referring to it as Parent, Parent.Print would be used.

The use of the new keyword here is only meant for shadowing, to tell the compiler that the child method is indeed hiding the parent method and not overriding it, but has no effect otherwise.

haim770
  • 48,394
  • 7
  • 105
  • 133
  • 1
    I never understood this line - "Child method is indeed hiding the parent method". If so, why the parent method is invoked when we don't override it. => Base b = new Child(). If the method is hidden by child then it should not have been called. – Ankush Jain Jun 12 '19 at 07:22
1

JCronin, you are casting to the Parent with Parent P = new Child(). To get the Child class behavior, you have to either cast it back to a Child (var x = (Child)P) or create the Child instance instance (Child P = new Child()).

See Downcasting

TheMule
  • 21
  • 3
0

Because you declared the type of P to be Parent. When you assign a Child to it, it will get cast to that type.

Daiku
  • 1,237
  • 11
  • 20