Confusion about virtual/new/override

后端 未结 5 1446
暗喜
暗喜 2020-12-15 01:06

I am a bit confused about the virtual/new/override thing. Here\'s an example:

class A
{
    public virtual void mVVirt         


        
5条回答
  •  天命终不由人
    2020-12-15 01:33

    Best way to think of it is that virtual methods use the actual (or concrete) type of the object to decide what implementation to execute, where non-Virtual methods use the 'declared type of the variabe you are using to access the method to decide which to run...

    Override means you are writing a method that is going to 'replace' the implementation for a virtual or abstract method (with the same name/signature) higher up the inheritance chain.

    new is used when there is a non-virtual method up the chain with the same name/signature, which the method you are adding will replace...

    The difference is as follows

    class base     { public virtual void  foo() { Console.write("base.foo"); } }
    class derived  { public override void foo() { Console.write("derived.foo"); } }
    base b = new base();
    b.foo()  // prints "base.foo" // no issue b is a base and variable is a base
    base b = new derived();
    b.foo(); // prints "derived.foo" because concrete tyoe is derived, not base
    

    but

    class base     { public void  foo() { Console.write("base.foo"); } }
    class derived  { public new void foo() { Console.write("derived.foo"); } }
    base b = new base();
    b.foo()  // prints "base.foo" // no issue b is a base and variable is a base
    base b = new derived();
    b.foo(); // prints "base.foo" because variable b is base. 
    derived d = b as derived;
    d.foo()    //  prints "derived.foo" - now variable d is declared as derived. 
    

    Your second call prints A::mvVirtual because that method (mVVirtual) is actually not virtual, (in spite of it's name), because it has the new specifier... So it decides based on the variable type, which is A.

    To explain what is going on technically, Every Type has a "method Table" with pointers to all the methods in that type. (It is NOT the instance of a type that has this table, It is the TYPE itself.) Each Types' method table is structured with all acessible virtual methods first, from object (furthest up the inheritance chain) at the beginning, to the virtual methods declared in the type itself, at the end. Then, after all the virtual methods are represented, all the non-virtual methods are added, again, from any non-virtual methods in object, first, all the way to any non-virtual methods in the Type itself. The table is structured this way so that the offsets for all virtual metods will be identical in all derived classes' method tables, since the compiler may call these methods from variables declared as other types, even from code in other methods declared and implemented in base types of the concrete class.

    When the compiler resolves a virtual method call it goes to the method table for the Type of the object itself, (the concrete type), whereas for a non-virtual call it goes to the method table for declared type of the variable. So if you call a virtual method, even from code in a base type, if the actual concrete type is Type derived from this base type, the compiler goes to the method table for that concrete type.

    If you call a non-virtual method, (no matter how far down the inheritance change the actual object's type might be), The compiler access the method table for the variab;es' declared type. This table has nothing in from any derived types furthur down the chain.

提交回复
热议问题