Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading across inheritance boundaries in c#?

After reading this article & that article - I got confused.

It says :

If there are two methods at different levels of the hierarchy, the "deeper" one will be chosen first, even if it isn't a "better function member" for the call.

Also -

It turns out that if you override a base class method in a child class, that doesn't count as declaring it.

Now let's go back to my question :

Case 1

    public class Base
     {
           public virtual void  Foo(int x)  { "1".Dump();}
     }

    public class Child : Base
     {
          public void Foo(object x) { "3".Dump();}  
          public override void  Foo(int x)  { "2".Dump();}
     }


void Main()
{
    Child c = new Child();
    c.Foo(10); //emits 3
}

OK.According to the article

"deeper" one will be chosen first, even if it isn't a "better function. and it doesn't count the override...

So it is right and the program emits "3". ( Foo(object x) is executed)

Let's change line order of 1 line :

Case 2

          public class Base
         {
                 public virtual void  Foo(int x)  { "1".Dump();}
                 public void Foo(object x) { "3".Dump();} //<line being moved here
         }

        public class Child : Base
         {
              public override void  Foo(int x)  { "2".Dump();}
         }


    void Main()
    {
        Child c = new Child();
        c.Foo(10); //emits 2 !!!!
    }

Now it emits "2".

Now lets change all int to object and all object to int :

Case 3

      public class Base
    {
      public virtual void  Foo(object x)  { "1".Dump();}
      public void Foo(int x) { "3".Dump();} 
    }

    public class Child : Base
    {
         public override void  Foo(object x)  { "2".Dump();}
    }


void Main()
{
    Child c = new Child();
    c.Foo(1); //emits "3"
}

Questions :


Question#1 : in case 2 , Child inherited the Foo(object x) from its father AND he also overrides a method.

but didnt we just say that :

It turns out that if you override a base class method in a child class, that doesn't count as declaring it

???

in fact, we didnt also declared the inherited function ... so what is the rule here in this situation ?


Question#2 : in case 3 , Child inherited the Foo(int x) from its father AND he also overrides a method.

but now , he chooses its father function....

it seems like override is winning only if it has exact match.

again , what is the rule here in this situation ?


like image 397
Royi Namir Avatar asked May 28 '12 14:05

Royi Namir


2 Answers

See member lookup process of a name N in a type T (in your case member Foo in type Child):

First, the set of all accessible (Section 3.5) members named N declared in T and the base types (Section 7.3.1) of T is constructed:

virtual void Foo(int x) // Base
void Foo(object x) // Base
override void Foo(int x) // Child

Declarations that include an override modifier are excluded from the set.

virtual void Foo(int x) // Base
void Foo(object x) // Base

Argument has an integer type. So, best choice here is (argument type matches parameter type)

virtual void Foo(int x) // Base

And this method called. But it is virtual method. And its invoked due to virtual method invocation mechanism:

For every virtual method declared in or inherited by a class, there exists a most derived implementation of the method with respect to that class. The most derived implementation of a virtual method M with respect to a class R is determined as follows:

  • If R contains the introducing virtual declaration of M, then this is the most derived implementation of M.
  • Otherwise, if R contains an override of M, then this is the most derived implementation of M.
  • Otherwise, the most derived implementation of M with respect to R is the same as the most derived implementation of M with respect to the direct base class of R.

And what is most derived implementation of virtual void Foo(int x) method with respect to a class Child? Yes, it is

override void Foo(int x) // Child

Which is invoked. Same rules applied in your third sample. But when two options left after overridden method removing, best choice (due to argument type) is non-virtual method.

like image 177
Sergey Berezovskiy Avatar answered Oct 21 '22 09:10

Sergey Berezovskiy


There are 2 things happening:

  1. When selecting the method to invoke, the compiler will obey the rules as per the linked articles - ie. a deeper method will be chosen before a shallower one even if the shallower one is a more specific match
  2. If you call an overridden method, it will always call the overridden method (this is separate to selecting which method to call), the "only" way to call the base method is from the subclass and using base.MyMethod(..)

So basically the lookup rules can choose the method taking an int if it's on a deeper class, but when the method gets called, if it's been overridden it will call the method taking an int on the child class.

like image 23
Martin Ernst Avatar answered Oct 21 '22 08:10

Martin Ernst