在方法表中,CLR赋予每个虚方法一个插槽,它将包含一个指向方法代码的指针。CLR假定被声明为newslot的虚方法与在基类型中声明的任何方法都无关。CLR赋予被声明为newslot的虚方法一个新的methodoffset,它比基类型所使用的最高methodcffset至少大1。由于对于所有具体类型的最终基类型System.Object来说它有四个虚方法,因此在每个方法表中,前四个插槽分别对应于这四个方法。
如果一个虚方法没有设置newslot元数据特性,那么,CLR假定该方法是基类型中虚方法的替代品。在这种情形下,CLR将在基类型的元数据中查找名字和签名匹配派生类型方法的虚方法。如果找到一个匹配,那么,该方法的methodoffset将会被重用,并且在派生类型的方法表中对应的插槽将会指向派生的替换方法。由于使用这个索引的调用是通过基类型的引用,因而对派生类型的调用将被分发到派生类型的方法,而不是基类型的方法,至于调用有可能通过基类型的引用发出,这个事实并不重要。
对于没有用newslot元数据特性标记的虚方法,被假定是基类型的虚方法的替换。然而,如果CLR在基类中没有发现匹配的方法,那么,它将假定该方法已被声明为newslot。
你可能会使用abstract或final特性要求或者禁止一个虚方法被替换。abstract特性要求派生类型必须替换虚方法.抽象力法只是声明而已,没有方法实现,原因就是必须通过派生类型进行替换,由此类推,包含一个或多个abstract方法的类型本身也必须被标记为abstract,因为这些类型的规范是不完整的,只有等到抽象方法被替换之后,才算完整的类型。因此,通过
接口声明的所有实例方法都要求被标记为abstract,绝大多数编程语言都隐式地这样处理。
当你替换基类型中的虚方法时,还可以禁止下游(downstream)的派生类型对该方法作进一步替换。通过设置final元数据特性就能够实现这点。将final特性应用到方法上,就等于告诉CLR,不允许在派生类型中替换该方法。显然,不能将newslot abstract特性和 final特性合在一起使用,因为前者要求由派生类型进行替换。
每种编程语言都提供了其自身的语法,用于指定virtual,abstract,newslot和final元数据特性。表6.2显示了由c#所使用的关键字。如前面提到的那样,在c#中把一个方法标记为new,并不影啊产生的代码或元数据,准确地说,该关键字只是消除了编译器的警告。
当一个派生类型提供一个实现以重写基类型的方法,对所有对于该方法的调用将分发到该派生类型的代码。考虑示例6.1所显示的类型层次,这里没有使用虚方法。注意,当一个程序调用基类型的Dolt方法时,该方法忽略了派生类型中DoltForReal方法的存在,并且只是简单地调用基类型的版本.因为在基类型中DoltForReal方法没有被声明为virtual,所以Base.DoIt的方法代码将被静态地绑定到调用Base.DoItForReal,而与任何派生类型无关。然而,如果在基类型中DoItForFeal方法被标记为virtual(如示例6.2所示),Base.Dolt方法将总是通过虚函数机制调用DoItForReal方法,它允许派生类型通过重写来替换基类型的方法。e