<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      happyhippy

      這個世界的問題在于聰明人充滿疑惑,而傻子們堅信不疑。--羅素

      (原文發表于CSDN我的Blog:http://blog.csdn.net/happyhippy/archive/2006/10/02/1317830.aspx
      昨天在某論壇上看到這個問題,覺得有點意思,就貼過來,順便貼下我對該問題的思考。
      具體問題是這樣的:

       GrandFather類中有一個虛方法
       
      class GrandFatherClass
       {
           
      public virtual void Func() {}
       }
       Father類重寫了這個方法
       
      class FatherClass:GrandFatherClass
       {
           
      public override void Func() {}
       }
      現在Child類想直接調用GrandFather類中的Func要怎么做
      ?
       
      class ChildClass:FatherClass
       {
           
      public void OtherFunc()
           {
               ((GrandFatherClass)
      this).Func();//不能調用GrandFatherClass中的Func().
               
      //GrandFatherClass.Func()如何調用?
           }
       }

      我用ILDasm工具反匯編上面代碼編譯生成的程序集,得到如下MSIL代碼:

      .method public hidebysig newslot virtual instance void  Func() cil managed
      {
        
      // 代碼大小       11 (0xb)
        .maxstack  8
        IL_0000:  ldstr      
      "GrandFather"
        IL_0005:  call       
      void [mscorlib]System.Console::WriteLine(string)
        IL_000a:  ret
      // end of method GrandFatherClass::Func

      .method 
      public hidebysig virtual instance void Func() cil managed
      {
        
      // 代碼大小       11 (0xb)
        .maxstack  8
        IL_0000:  ldstr      
      "Father"
        IL_0005:  call       
      void [mscorlib]System.Console::WriteLine(string)
        IL_000a:  ret
      // end of method FatherClass::Func

      .method 
      public hidebysig instance void  OtherFunc() cil managed
      {
        
      // 代碼大小       7 (0x7)
        .maxstack  8
        IL_0000:  ldarg.
      0
        IL_0001:  callvirt   instance 
      void MyProject.GrandFatherClass::Func()
        IL_0006:  ret
      // end of method ChildClass::OtherFunc

              我查了下MSDN,找到了這句話:“調用虛方法時,將為重寫成員檢查該對象的運行時類型。將調用大部分派生類中的該重寫成員,如果沒有派生類重寫該成員,則它可能是原始成員。”也就是說,即使我們在ChildClass中執行((GrandFatherClass)this).Func()(從IL代碼中我們也可以看到是在調用GrandFather的Func()方法),CLR檢查到對象的運行時類型為ChildClass,而且ChildClass有重寫了自己GrandFatherClass中的Func()(從FatherClass中繼承而來),所以該語句仍會調用從FatherClass繼承而來的Func()方法。
              這里只是從表象上解釋了原因,下面這篇《深入探索.NET框架內部了解CLR如何創建運行時對象》則從底層剖析了CLR對象模型,理解了CLR對象模型,我們就可以更加清楚地理解CLR中的方法分派(Dispatch)機制。
              用IL和方法表布局來解釋如上代碼中的行為就是:在方法表中,CLR賦予每個虛方法一個方法槽(Slot),它將包含一個指向方法代碼的指針(實際上是通過MethodDesc間接來指向該地址,上面這篇《深入探索……》里面將得比較清楚了,我不再贅述);FatherClass重寫了GrandFather的Func()虛方法,它替換被覆蓋的虛方法(Func),Func方法槽指向FatherClass實現的Func方法的地址。虛分派總是通過一個固定的槽編號Func()發生,和方法表指針在特定的類(類型)實現層次無關。在方法表布局時,類加載器用覆蓋的子類的實現FatherCalss.Func()代替父類的實現GrandFather.Func()。結果,對父對象的方法調用被分派到子對象的實現。
             下圖是運行時對ChildClass中OtherFunc()反匯編得到的結果(可在調試時通過在命令窗口中輸入disasm,可以查看IA-32匯編指令):
            從圖中我們可以看到,調用一個虛方法要執行三條IA-32匯編指令:
            mov ecx,esi                 ;將目標對象的引用(在這里是this)存儲在IA-32 ecx寄存器中
            mov eax,dword ptr[ecx]      ;這是針對虛方法調用的指令,將對象的類型句柄存儲在eax寄存器中
            call dword ptr [eax+offset] ;通過對象的類型句柄和方法在方法表中的偏移量來定位目標方法的實際地址
            從圖中我們也可以看到,不論我們執行((FatherClass)this).Func()還是執行((GrandFatherClass)this).Func(),都是在調用偏移量為38h所指向的方法(ChildClass的Func()只有這一個插槽)。
            所以按照上面繼承/重寫的寫法,不能實現調用GrandFatherClass中的Func()。要實現調用GrandFather中的方法,可按如下兩種方法:

      法一:

      class GrandFatherClass
      {
          
      public virtual void Func() { Console.WriteLine("GrandFather"); }
      }
      class FatherClass : GrandFatherClass
      {
          
      public new virtual void Func() { Console.WriteLine("Father"); }
          
      //加不加關鍵字new都沒有關系,這里加new的作用只是消除編譯器警告信息,不會對生成的IL代碼產生任何影響。
      }
      class ChildClass : FatherClass
      {
          
      public void OtherFunc()
          {
            ((GrandFatherClass)
      this).Func();
          }
      }

      //對應的MSIL代碼:
      .method public hidebysig newslot virtual instance void  Func() cil managed
      {
        
      // 代碼大小       11 (0xb)
        .maxstack  8
        IL_0000:  ldstr      
      "GrandFather"
        IL_0005:  call       
      void [mscorlib]System.Console::WriteLine(string)
        IL_000a:  ret
      // end of method GrandFatherClass::Func
      .method public hidebysig newslot virtual instance void  Func() cil managed
      {
        
      // 代碼大小       11 (0xb)
        .maxstack  8
        IL_0000:  ldstr      
      "Father"
        IL_0005:  call       
      void [mscorlib]System.Console::WriteLine(string)
        IL_000a:  ret
      // end of method FatherClass::Func
      .method public hidebysig instance void  OtherFunc() cil managed
      {
        
      // 代碼大小       7 (0x7)
        .maxstack  8
        IL_0000:  ldarg.
      0
        IL_0001:  callvirt   instance 
      void MyProject.GrandFatherClass::Func()//這里生成的是callvirt調用命令
        IL_0006:  ret
      // end of method ChildClass::OtherFunc

              從IL代碼中我們可以看到,FatherClass::Func上有應用newslot標示,CLR賦予被申明為newslot的虛方法一個新的methodoffset,所以這里并沒有覆蓋GrandFatherClass::Func(),而在FatherClass的方法表中的方法槽表(Method Slot Table)中,也同時存在兩個Func()槽,一個是繼承而來的,其指向GrandFather的Func()實現,另一個槽執行自身的實現。而ChildClass繼承自FatherClass,所以ChildClass中的方法表中,也有兩個Func()槽。在下圖中,我們也可以看到,這兩個方法在方法表中偏移量,一個為38H,另一個為3CH。

      法二:

          class GrandFatherClass
          
      {
              
      public void Func() { Console.WriteLine("GrandFather"); }
          }


          
      class FatherClass : GrandFatherClass
          
      {
              
      public new void Func() { Console.WriteLine("Father"); }
          }


          
      class ChildClass : FatherClass
          
      {
              
      public void OtherFunc()
              
      {
                  ((GrandFatherClass)
      this).Func();
              }

          }


      //MSIL:
      .method public hidebysig instance void  Func() cil managed
      {
        
      // 代碼大小       11 (0xb)
        .maxstack  8
        IL_0000:  ldstr      
      "GrandFather"
        IL_0005:  call       
      void [mscorlib]System.Console::WriteLine(string)
        IL_000a:  ret
      }
       // end of method GrandFatherClass::Func
      .method public hidebysig instance void  Func() cil managed
      {
        
      // 代碼大小       11 (0xb)
        .maxstack  8
        IL_0000:  ldstr      
      "Father"
        IL_0005:  call       
      void [mscorlib]System.Console::WriteLine(string)
        IL_000a:  ret
      }
       // end of method FatherClass::Func
      .method public hidebysig instance void  OtherFunc() cil managed
      {
        
      // 代碼大小       7 (0x7)
        .maxstack  8
        IL_0000:  ldarg.
      0
        IL_0001:  call       instance 
      void MyProject.GrandFatherClass::Func()//這里生成的是call調用命令
        IL_0006:  ret
      }
       // end of method ChildClass::OtherFunc

             仔細觀察IL代碼,我們會發現這里生成的是call指令(而前面兩個調用虛方法時生成的是callvirt指令),IL中的call指令生成2條IA-32匯編指令:
      mov ecx,esi                 ;把目標對象的引用放進ecx寄存器
      call methodAddress  ;直接調用methodAddress指向的目標方法

       

           另外:FatherClass既然已經重寫了其父類GrandFather中的Viturl方法Func(),而其子類ChildClass卻要拒絕接受其重寫的Func(),感覺這種繼承體系本身就存在一些問題,可以考慮重構一下該繼承體系,具體可參考Martin Fowler的《重構-改善既有代碼的設計》中Refused Bequest(被拒絕的遺贈)一節。

      posted on 2006-12-23 10:56  Silent Void  閱讀(439)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 777米奇色狠狠俺去啦| 日韩一区二区三区高清视频| 久久免费偷拍视频有没有| 丁香婷婷综合激情五月色| 久久亚洲日本激情战少妇| 亚洲精品色一区二区三区| 亚洲国产精品成人av网| 高清国产一区二区无遮挡| 国产一区二区三区在线观看免费| 国产成人精品av| 国产成人精品亚洲精品密奴| 亚洲狠狠爱一区二区三区| 伊人精品成人久久综合97| 狠狠色噜噜狠狠狠狠2021| 日韩免费无码视频一区二区三区| 国产精品熟女孕妇一区二区| 亚洲va久久久噜噜噜久久狠狠| 成人国产精品免费网站| 精品一区二区亚洲国产| 国产精品爽爽v在线观看无码| 体态丰腴的微胖熟女的特征| 国产午夜福利视频在线| 红原县| 无码少妇一区二区| 玩弄漂亮少妇高潮白浆| 镇赉县| 极品无码国模国产在线观看| 国产丝袜视频一区二区三区 | 亚洲男人电影天堂无码| 日韩无套无码精品| 国产精品疯狂输出jk草莓视频| 国产精品十八禁在线观看| 国产女人高潮视频在线观看| 国内精品伊人久久久久av| 亚洲国产精品乱码一区二区| 四虎影院176| 最新中文字幕国产精品| 国产情侣草莓视频在线| 开心五月激情综合久久爱| 五月天免费中文字幕av| 亚洲中文字幕国产综合|