开发者

Virtual base members not seeing overrides?

I always thought base.Something was equivalent to ((Parent)this).Something, but apparently that's not the case. I thought that overriding methods eliminated the possibility of the original virtual method being called.

Why is the third output different?

void Main() {
    Child child = new Child();

    child.Method();             //output "Child here!"
    ((Parent)child).Method();   //output "Chi开发者_如何学运维ld here!"
    child.BaseMethod();         //output "Parent here!"
}

class Parent {
    public virtual void Method() { 
        Console.WriteLine("Parent here!"); 
    }
}

class Child : Parent {
    public override void Method() { 
        Console.WriteLine ("Child here!"); 
    }
    public void BaseMethod() { 
        base.Method(); 
    }
}


Because in BaseMethod you explicitly call the method in the base class, by using the base keyword. There is a difference between calling Method() and base.Method() within the class.

In the documentation for the base keyword, it says (amongst other things) that it can be used to Call a method on the base class that has been overridden by another method.


((Parent)this).foo for virtual method foo is still/always a virtual method call. The target address will be looked up from the class's virtual method table, which will always land you at the most derrived implementation for the type of the object instance. You can cast it to parent all you want, but that doesn't change the vtable used to dispatch the call at runtime.

The base keyword makes the call resolve as a non-virtual call, so that you can reach the ancestor implementation from within a descendant implementation. There is no address lookup at runtime, the address is resolved at compile time.


C# Language specification:

At compile-time, base-access expressions of the form base.I and base[E] are evaluated exactly as if they were written ((B)this).I and ((B)this)[E], where B is the base class of the class or struct in which the construct occurs.

When a base-access references a virtual function member (a method, property, or indexer), the determination of which function member to invoke at run-time (§7.4.4) is changed. The function member that is invoked is determined by finding the most derived implementation (§10.6.3) of the function member with respect to B (instead of with respect to the run-time type of this, as would be usual in a non-base access).

I.e. base.Something is equivalent to ((Parent)this).Something but only for non-virtual members otherwise semantics is different.


I believe you misunderstand base.Something(). base specifically calls the base classes (possibly) overriden implementation of a method or property. From MSDN:

The base keyword is used to access members of the base class from within a derived class:

Call a method on the base class that has been overridden by another method.has been overridden by another method.

Note that ((Parent)this).Something() would only affect what is called if you used new to hide a method instead of override a virtual.


Casting the child as type of parent does not change the functions that are going to be called because they've been overridden on the object. That's part of the beauty of inheritance (polymorphism).

In the BaseMethod you call base.Method, which is a way of getting access to the parent function (if you need it) but if you have an array of type Shape and in it are different subclasses of shape, you want the .Draw() method to call the subclass not the superclass method (by default).


This has to do with understanding polymorphism.

http://en.wikipedia.org/wiki/Type_polymorphism

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜