虚拟基础成员没有看到覆盖?

时间:2010-08-31 19:19:44

标签: c# inheritance

我一直认为base.Something相当于((Parent)this).Something,但显然事实并非如此。我认为重写方法消除了调用原始虚方法的可能性。

为什么第三个输出不同?

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

    child.Method();             //output "Child here!"
    ((Parent)child).Method();   //output "Child 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(); 
    }
}

6 个答案:

答案 0 :(得分:5)

因为在BaseMethod中您显式地使用base关键字在基类中调用该方法。在课程中调用Method()base.Method()之间存在差异。

base关键字的文档中,它说(除其他外)它可以用于调用已被另一个方法覆盖的基类上的方法

答案 1 :(得分:3)

((Parent)this).foo对于虚方法foo仍然/始终是虚方法调用。将从类的虚方法表中查找目标地址,该表将始终位于对象实例类型的最繁琐的实现中。您可以根据需要将其强制转换为父级,但这不会更改用于在运行时调度调用的vtable。

base关键字将调用解析为非虚拟调用,以便您可以从后代实现中访问祖先实现。运行时没有地址查找,地址在编译时解析。

答案 2 :(得分:3)

C#语言规范:

  

在编译时, base-access   表格形式base.I和   base [E]完全被评估为   他们写的((B)这个。)我和   ((B)this)[E],其中B是基数   其中的类或结构的类   构造发生。

     

base-access 引用a时   虚函数成员(一种方法,   属性或索引器),   确定哪个功能成员   在运行时调用(第7.4.4节)是   改变。函数成员是   调用是通过查找来确定的   大多数派生的实现(§10.6.3)   函数成员的关于   B(而不是相对于   这样的运行时类型   通常在非基础访问中。)

即。 base.Something相当于((Parent)this)。但只有非虚拟成员才有,但语义不同。

答案 3 :(得分:2)

我相信你误解了base.Something()base专门调用基类(可能)覆盖方法或属性的实现。 From MSDN

  

base关键字用于访问   来自内部的基类成员   派生类:

     

在基类上调用一个方法   已被另一种方法覆盖。已被另一种方法覆盖。

请注意((Parent)this).Something()只会影响您使用new隐藏方法而不是虚拟override时所调用的内容。

答案 4 :(得分:1)

将子项作为父类型进行转换不会更改将要调用的函数,因为它们已在对象上被覆盖。这是继承之美(多态)的一部分。

在BaseMethod中你调用base.Method,这是一种访问父函数的方法(如果你需要)但是如果你有一个Shape类型的数组,并且在它中是不同的形状子类,你想要.Draw()方法调用子类而不是超类方法(默认情况下)。

答案 5 :(得分:0)

这与理解多态性有关。

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