2009-09-06 39 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