zoukankan      html  css  js  c++  java
  • .NET 调用虚方法1 转

    最近一直对.net framework中,虚方法的调用是如何实现这个问题有些疑惑,在看了Essential .Net关于Method的那一章和Artech推荐的文章Drill Into .NET Framework Internals to See How the CLR Creates Runtime Objects以后,还是一知半解,有些疑惑得不到答案。主要有这些:

    •   父类定义的非虚方法是否在子类中有拷贝?
    •   虚方法是如何实现多态的?
    •   子类继承父类的虚方法实现是否和继承非虚方法机制相同?
    •   如果子类隐藏了父类的虚方法,这又是怎样实现的?

      当然问题不止这么多,关于接口方面还有很多很多疑惑,不过时间有限,一下也没办法全部弄清楚,有时间慢慢研究。我主要使用Windbg工具来跟踪调试,关于这个工具如何使用,Google一下就会有很多了。

      这些都是我自己研究加上参考资料所得,如果有不对的地方,希望大家讨论指出。

      首先看下面这段代码:

     public class Base
     {
         public virtual void VirtualFun1()
         {
             Console.WriteLine("Base.VirtualFun1");
         }
         public void NoneVirtualFun1()
         {
             System.Console.WriteLine("Base.NoneVirtualFun1");
         }
         public virtual void VirtualFun2()
         {
             System.Console.WriteLine("Base.VirtualFun2");
         }
         public virtual void VirtualFun3()
         {
             System.Console.WriteLine("Base.VirtualFun3");
         }
     }
    
     public class Derived : Base
     {
         public override void VirtualFun1()
         {
             Console.WriteLine("Derived.VirtualFun1");
         }
         public new virtual void VirtualFun2()
         {
             System.Console.WriteLine("Derived.VirtualFun2");
         }
         public virtual void VirtualFun4()
         {
             System.Console.WriteLine("Derived.VirtualFun4");
         }
    
     }
    

    Base类是基类,它包含三个虚方法VirtualFun1, VirtuaFun2, VirtualFun3和一个非虚方法NoneVirtualFun1。

    Derived继承Base类,它重写了VirtualFun1虚方法,隐藏了Base类的VirtualFun2虚方法,然后又增加了VirtualFun4虚方法。

    看看一个Base类的实例在内存中是怎样排布的:

    image

      Object Ref表示某Base实例的引用,它指向在GC Heap中分配的Base对象,这个对象可以分为三部分:同步块索引、类型指针和字段。主要来关注类型指针,它指向该类型的Method Table,这其实是在Load Heap中分配的Type类型对象,所有该类型的实例的类型指针都指向同一个Method Table(这里表示所有Base对象的类型指针都指向同一个Method Table)。

      Method Table里面包含很多信息,这里关注有关Method这一区域,(如果想了解更详细的method table,请参考上面的文章)。

      根据在Method Table里的信息,可以知道它包含9个Method(其实应该有个字段标示有多少个虚方法,这里就没画了)。接下来就是这些method,它分为两部分,前面一部分是所有的虚方法,后面的是非虚方法。因为所有的类型都是继承自System.Object类,所以前四个方法是Object类的虚方法(ToString, Equals, GetHashCode, Finalize),接着是Base类定义的三个虚方法(VirtualFun1, VirtualFun2, VirtualFun3),最后是Base类的非虚方法NoneVirtualFun1以及默认的构造函数。下面再来看看Derived类型的Method Table:

    image

    仔细对比一下这两个Method Table,可以发现这样几个特点:

    • Base类中的所有虚方法在Derived类的Method Table中一一对应
    • Base类中的所有非虚方法在Derived类中的Method Table并没有拷贝(这一点回答了上面的第一个问题)
    • Derived类新增的虚方法都添加到继承自Base类的虚方法的后面
    • 如果Derived类override Base类的虚方法,它就将该方法指向自身的实现
    • 如果Derived类使用new关键字隐藏了Base类虚方法的实现,它就相当于增加了一个虚方法,而不是覆盖。

    下面看看调用虚方法时如何实现多态,比如有这样一段代码

      Base b = new Derived();

      b.VirtualFun1();

    编译后在我的机器上会生成这样的汇编代码:

      mov ecx, esi

      mov eax, dword ptr[ecx]

      call dword ptr [eax + 3ch]

      现在来解释这几句代码:mov ecx, esi 是将新构造的对象的地址保存在ecx寄存器中; mov eax, dword ptr[ecx] 表示ecx的值是一个指针(根据上面的图可以知道对象的头4个字节保存的是method table的地址),它将method table的地址保存到eax寄存器中,最后call dword ptr[eax + 3ch]。3ch表示偏移量,它表示该方法相对于该method table的偏址,是在该类型加载到load heap以后确定的。这样,由method table的地址加上method相对与method table的偏移量,就可以唯一确定一个方法。

      这样在调用b.VirtualFun1(); 时,由于b是Derived类的实例,所以根据它指向的托管对象找到的method table是Derived类型的method table,就能正确调用该方法。因为Derived类中override了VirtualFun1这个虚方法,所以调用的是Derived类的实现,而如果没有override基类的虚方法,它就指向基类的该方法的实现。

      由此可以看出,CLR实现虚方法的机制主要是通过类型的method table加上该虚方法相对于method table的偏移量来确定调用具体方法的。一个虚方法在整个继承体系所有类型对应的method table中的偏移量是固定的,比如VirtualFunc1在Base类型的method table中的偏移量是3ch,它在Derived类型的method table中的偏移量也是3ch,如果还有继承自Derived类的类,也是同样,利用这种机制就实现了多态。

      结论

    •   每个类型对应一个Method Table
    •   子类的Method Table中包含父类的所有虚方法,而不包含父类的非虚方法
    •   CLR根据对象找到它对应类型的method table,然后根据该虚方法在method table中的偏移量实现多态调用。


    系列文章:  CLR怎样实现虚方法的多态调用(2) 
    本文地址: http://www.cnblogs.com/blusehuang/archive/2007/07/27/833593.html

  • 相关阅读:
    leetcode 350. Intersection of Two Arrays II
    leetcode 278. First Bad Version
    leetcode 34. Find First and Last Position of Element in Sorted Array
    leetcode 54. Spiral Matrix
    leetcode 59. Spiral Matrix II
    leetcode 44. Wildcard Matching
    leetcode 10. Regular Expression Matching(正则表达式匹配)
    leetcode 174. Dungeon Game (地下城游戏)
    leetcode 36. Valid Sudoku
    Angular Elements
  • 原文地址:https://www.cnblogs.com/qianyz/p/2774791.html
Copyright © 2011-2022 走看看