2009-09-06 57 views
2

假設我有代碼段如下:(澄清目的/未很好地形成C# - CLR如何在繼承期間組織內存/引用?

class Employee 
{ 
    #region fields 

    protected string _empID; 

    protected string _empName; 

    protected readonly string _ssn; 

    #endregion 

    public Employee(){} 

    public Employee(string _empID,string _empName,string _ssn) 
    { 
     this._empID =_empID; 
     this._empName=_empName; 
     this._ssn = _ssn; 
    } 
} 


class Manager : Employee 
{ 
    private string _branchID; 

    public Manager(int _branchID):base(string _empID,string _empName,string _ssn) 
    { 
     this._branchID=_branchID; 
    } 
} 

static void Main() 
{ 
    Manager mgr = new Manager("1","sam","xxx","Branch1"); 
} 

使用關鍵字我調用父類的構造

在這種情況下繼承是如何組織的?我有一些壞的假設如下:

的經理是從員工獲得,管理類充滿(EMPID,empName,SSN)

----------------- 
Manager 
----------------- 
empID 
empName 
ssn 
branchID 

第1步:構造函數調用:基地( 「1」, 「SAM」, 「XXX」)

步驟2:基類(員工)構造填充日提交(EMPID,empName派生類,SSN)

步驟3:branchID由分配派生類的構造

.......

我的問題是

  • 如果一個類從基類派生,派生類也有基類的隱藏字段?
  • 派生類共享基類字段?我的意思是單獨的內存塊分配給基類和派生類?
  • 回答

    5

    http://www.rvenables.com/linkjackandsufferaccidentaldroptable/clr_via_csharp_f4.9.png

    是,派生類也將包含在存儲器中的基類的字段。在CLR的第112頁上,通過C#,Jeffrey Richter說:

    「然後,M3執行它的代碼來構造一個管理器對象,這會導致在管理堆中創建一個Manager類型的實例Manager對象,如圖4-9所示,正如你看到的那樣,Manager對象(與所有對象一樣)具有類型對象指針和同步塊索引該對象還包含保存所有實例數據字段所需的字節Manager類型爲由Manager類型的任何基類(在本例中爲Employee和Object)定義的任何實例字段。「 (強調已添加)

    還值得注意的是,爲任何基本類型創建的單獨的內存塊。但只適用於類型數據(最多隻能使用一次)。當您創建Manager對象(派生自Employee)時,CLR將確保在堆上存在經理類型對象員工類型對象。 1)裏奇特,傑弗裏。 CLR通過C#。微軟出版社,2006年。 (Amazon Link

    +0

    哇!感謝您的關心和花費您的時間來解釋細節。我真的很感激你。 – user160677 2009-09-06 16:50:41

    7

    一個對象以包含指向其實際類型信息的指針的頭開始。該類型的信息包括vtable來確定哪種方法實際上意味着什麼。 CLR在執行時使用該vtable來調用重寫的方法。

    對象頭到來後全部與對象關聯的實例數據 - 包括基類字段和派生類字段。它都在一個地方 - 它不像派生類的實例也有一個對基類的「隱藏」實例的引用。我強烈懷疑基類字段第一,因爲然後基類中的方法仍然可以引用(在彙編中)通過對象的「頂部」的偏移相同的領域......但我沒有任何在我面前證實這一點。

    IIRC,Jeff Richter的"CLR via C#"在一定深度上討論了所有這些 - 這對於這類事情來說是一個很好的信息來源。

    +1

    關於p110-116的相關討論。 – 2009-09-06 16:29:35

    2

    您可以將對象想象爲具有可以放入方法和字段的「插槽」......基類將具有用於字段的時隙1,2,3,並且方法有插槽4 。如果你創建派生類,一個新的字段將添加另一個插槽(例如插槽5)。

    這樣,使用基類類型的變量仍然可以訪問正確的字段,而不必擔心差異。派生類的構造函數必須首先調用基類構造函數,即使您沒有在代碼中明確指定它。

    如果你的slot-4方法是虛擬的,並且你的派生類重寫它,你再次把重寫方法放在第4個插槽中,如果你隱藏它(通過new),它會分配一個新的插槽通過派生類的變量調用)。

    那麼我就是這麼想的。一種簡化的方式,但它有幫助。我認爲它可能是一個內存塊,但是再次,這是一個實現細節。

    +0

    非常感謝您提供這些信息。 – user160677 2009-09-06 16:54:09