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

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

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

      [你必須知道的.NET]第十五回:繼承本質論

      [你必須知道的.NET]

      第十五回:繼承本質論

      發布日期:2007.9.10 作者:Anytao
      ?2007 Anytao.com ,原創作品,轉貼請注明作者和出處。

      本文將介紹以下內容:

      • 什么是繼承?
      • 繼承的實現本質

       

      1. 引言

      關于繼承,你是否駕熟就輕,關于繼承,你是否了如指掌。

      本文不討論繼承的基本概念,我們回歸本質,從編譯器運行的角度來揭示.NET繼承中的運行本源,來發現子類對象是如何實現了對父類成員與方法的繼承,以最為簡陋的示例來揭示繼承的實質,闡述繼承機制是如何被執行的,這對于更好的理解繼承,是必要且必然的。

      2. 分析

      下面首先以一個簡單的動物繼承體系為例,來進行說明:

          public abstract class Animal

          {

              public abstract void ShowType();

              public void Eat()

              {

                  Console.WriteLine("Animal always eat.");

              }

          }

          public class Bird: Animal

          {

              private string type = "Bird";

              public override void ShowType()

              {

                  Console.WriteLine("Type is {0}", type);

              }

              private string color;

              public string Color

              {

                  get { return color; }

                  set { color = value; }

              }

          }

          public class Chicken : Bird

          {

              private string type = "Chicken";

              public override void ShowType()

              {

                  Console.WriteLine("Type is {0}", type);

              }

              public void ShowColor()

              {

                  Console.WriteLine("Color is {0}", Color);

              }

          }


      然后,在測試類中創建各個類對象,由于Animal為抽象類,我們只創建Bird對象和Chicken對象。

          public class TestInheritance

          {

              public static void Main()

              {

                  Bird bird = new Bird();

                  Chicken chicken = new Chicken();

              }

          }


      下面我們從編譯角度對這一簡單的繼承示例進行深入分析,從而了解.NET內部是如何實現我們強調的繼承機制。

      (1)我們簡要的分析一下對象的創建過程:

                  Bird animal = new Bird();

      Bird bird創建的是一個Bird類型的引用,而new Bird()完成的是創建Bird對象,分配內存空間和初始化操作,然后將這個對象賦給bird引用,也就是建立bird引用與Bird對象的關聯。

      (2)我們從繼承的角度來分析在編譯器編譯期是如何執行對象的創建過程,因為繼承的本質就體現于對象的創建過程。

      在此我們以Chicken對象的創建為例,首先是字段,對象一經創建,會首先找到其父類Bird,并為其字段分配存儲空間,而Bird也會繼續找到其父類Animal,為其分配存儲空間,依次類推直到遞歸結束,也就是完成System.Object內存分配為止。我們可以在編譯器中單步執行的方法來大致了解其分配的過程和順序,因此,對象的創建過程是按照順序完成了對整個父類及其本身字段的內存創建,并且字段的存儲順序是由上到下排列,object類的字段排在最前面,其原因是如果父類和子類出現了同名字段,則在子類對象創建時,編譯器會自動認為這是兩個不同的字段而加以區別。

      然后,是方法表的創建,必須明確的一點是方法表的創建是類第一次加載到CLR時完成的,在對象創建時只是將其附加成員TypeHandle指向方法列表在Loader Heap上的地址,將對象與其動態方法列表相關聯起來,因此方法表是先于對象而存在的。類似于字段的創建過程,方法表的創建也是父類在先子類在后,原因是顯而易見的,類Chicken生成方法列表時,首先將Bird的所有方法拷貝一份,然后和Chicken本身的方法列表做以對比,如果有覆寫的虛方法則以子類方法覆蓋同名的父類方法,同時添加子類的新方法,從而創建完成Chicken的方法列表。這種創建過程也是逐層遞歸到Object類,并且方法列表中也是按照順序排列的,父類在前子類在后,其原因和字段大同小異,留待讀者自己體味。

      結合我們的分析過程,現在將對象創建的過程以簡單的圖例來揭示其在內存中的分配情形,如下:

       

      從我們的分析,和上面的對象創建過程可見,對繼承的本質我們有了更明確的認識,對于以下的問題就有了清晰明白的答案:

      • 繼承是可傳遞的,子類是對父類的擴展,必須繼承父類方法,同時可以添加新方法。
      • 子類可以調用父類方法和字段,而父類不能調用子類方法和字段。
      • 虛方法如何實現覆寫操作,使得父類指針可以指向子類對象成員。
      • new關鍵字在虛方法繼承中的阻斷作用。

      你是否已經找到了理解繼承、理解動態編譯的不二法門。

      3. 思考

      通過上面的講述與分析,我們基本上對.NET在編譯期的實現原理有了大致的了解,但是還有以下的問題,一定會引起一定的疑惑,那就是:

                  Bird bird2 = new Chicken();

      這種情況下,bird2.ShowType應該返回什么值呢?而bird2.type有該是什么值呢?有兩個原則,是.NET專門用于解決這一問題的:

      • 關注對象原則:調用子類還是父類的方法,取決于創建的對象是子類對象還是父類對象,而不是它的引用類型。例如Bird bird2 = new Chicken()時,我們關注的是其創建對象為Chicken類型,因此子類將繼承父類的字段和方法,或者覆寫父類的虛方法,而不用關注bird2的引用類型是否為Bird。引用類型不同的區別決定了不同的對象在方法表中不同的訪問權限。

      注意

      根據關注對象原則,那么下面的兩種情況又該如何區別呢?

                  Bird bird2 = new Chicken();

                  Chicken chicken = new Chicken();

      根據我們上文的分析,bird2對象和chicken對象在內存布局上是一樣的,差別就在于其引用指針的類型不同:bird2為Bird類型指針,而chicken為Chicken類型指針。以方法調用為例,不同的類型指針在虛擬方法表中有不同的附加信息作為標志來區別其訪問的地址區域,稱為offset。不同類型的指針只能在其特定地址區域內進行執行,子類覆蓋父類時會保證其訪問地址區域的一致性,從而解決了不同的類型訪問具有不同的訪問權限問題。

       
      • 執行就近原則:對于同名字段或者方法,編譯器是按照其順序查找來引用的,也就是首先訪問離它創建最近的字段或者方法,例如上例中的bird2,是Bird類型,因此會首先訪問Bird_type(注意編譯器是不會重新命名的,在此是為區分起見),如果type類型設為public,則在此將返回“Bird”值。這也就是為什么在對象創建時必須將字段按順序排列,而父類要先于子類編譯的原因了。

      思考

      1. 上面我們分析到bird2.type的值是“Bird”,那么bird2.ShowType()會顯示什么值呢?答案是“Type is Chicken”,根據本文上面的分析,想想到底為什么?

      2. 關于new關鍵字在虛方法動態調用中的阻斷作用,也有了更明確的理論基礎。在子類方法中,如果標記new關鍵字,則意味著隱藏基類實現,其實就是創建了與父類同名的另一個方法,在編譯中這兩個方法處于動態方法表的不同地址位置,父類方法排在前面,子類方法排在后面。

       

      4. 結論

      在.NET中,如果創建一個類,則該類總是在繼承。這緣于.NET的面向對象特性,所有的類型都最終繼承自共同的根System.Object類??梢?,繼承是.NET運行機制的基礎技術之一,一切皆為對象,一切皆于繼承。本文從基礎出發,深入本質探索本源,分析疑難比較鑒別。對于什么是繼承這個話題,希望每個人能從中尋求自己的答案,理解繼承、關注封裝、玩轉多態是理解面向對象的起點,希望本文是這一旅程的起點。
       

      [祝福]
      僅以此篇獻給我的老師們:湯文海老師,陳樺老師。 

      參考文獻

      (USA)Don Box, Essential .NET

      (中國)蟲蟲,從編譯的角度看對象

       

      溫故知新

      [開篇有益]
      [第一回:恩怨情仇:is和as]
      [第二回:對抽象編程:接口和抽象類]
      [第三回:歷史糾葛:特性和屬性]
      [第四回:后來居上:class和struct]
      [第五回:深入淺出關鍵字---把new說透]
      [第六回:深入淺出關鍵字---base和this]
      [第七回:品味類型---從通用類型系統開始]
      [第八回:品味類型---值類型與引用類型(上)-內存有理]
      [第九回:品味類型---值類型與引用類型(中)-規則無邊]
      [第十回:品味類型---值類型與引用類型(下)-應用征途]
      [第十一回:參數之惑---傳遞的藝術(上)]
      [第十二回:參數之惑---傳遞的藝術(下)]
      [第十三回:從Hello, world開始認識IL]
      [第十四回:認識IL代碼---從開始到現在]

      ?2007 Anytao.com

      原創作品,轉貼請注明作者和出處,留此信息。

      本貼子以現狀提供且沒有任何擔保,同時也沒有授予任何權利。
      This posting is provided "AS IS" with no warranties, and confers no rights.

      posted @ 2007-09-10 21:43  Anytao  閱讀(19117)  評論(110)    收藏  舉報
      主站蜘蛛池模板: 永仁县| 国产乱码精品一区二三区| 影音先锋AV成人资源站在线播放| 国产精品不卡一二三区| 无码一区二区三区av在线播放| 图片区偷拍区小说区五月| 男人猛躁进女人免费播放| 亚洲av色香蕉一二三区| 国产精品天干天干综合网| 国产一区二区高清不卡| 色国产视频| 国产精品久久久久不卡绿巨人| 少妇xxxxx性开放| 日本中文字幕乱码免费| 国产精品普通话国语对白露脸| 关岭| 亚洲乱熟乱熟女一区二区 | 国产成人毛片无码视频软件| 国产白丝jk捆绑束缚调教视频| 女同亚洲精品一区二区三| 中文字幕av一区二区| 久章草在线精品视频免费观看| 亚洲最大av一区二区| 亚洲AV无码专区亚洲AV紧身裤 | 亚洲av无码成人精品区一区| 久久精品国产亚洲av麻豆小说| 久久99国产精品久久99小说| 施甸县| 久久久av男人的天堂| 熟妇女人妻丰满少妇中文字幕| 成人国产精品一区二区网站公司 | 久久夜色撩人国产综合av| 本免费Av无码专区一区| 年轻女教师hd中字3| 国产精品亚洲五月天高清| 无码日韩精品一区二区三区免费| 亚洲国产成人资源在线| 99久久亚洲综合网精品| 国产精品天天看天天狠| 日韩熟女熟妇久久精品综合| 亚洲二区中文字幕在线|