C#-CLR在继承过程中如何组织内存/引用?

C#-CLR在继承过程中如何组织内存/引用?,c#,.net,oop,inheritance,C#,.net,Oop,Inheritance,假设我有如下代码片段:(澄清目的/格式不正确) 使用base关键字调用父类构造函数 在这种情况下,继承是如何组织的?我有以下一些不好的假设: 由于Manager是从Employee派生的,所以Manager类用(empID、empName、ssn)填充 步骤1:构造函数调用:base(“1”、“sam”、“xxx”) 步骤2:基类(Employee)构造函数填充派生类字段(empID、empName、ssn) 步骤3:branchID由派生类构造函数赋值 我的问题是 如果一个类是从基类派生的

假设我有如下代码片段:(澄清目的/格式不正确)

使用base关键字调用父类构造函数

在这种情况下,继承是如何组织的?我有以下一些不好的假设:

由于Manager是从Employee派生的,所以Manager类用(empID、empName、ssn)填充

步骤1:构造函数调用:base(“1”、“sam”、“xxx”)

步骤2:基类(Employee)构造函数填充派生类字段(empID、empName、ssn)

步骤3:branchID由派生类构造函数赋值

我的问题是

  • 如果一个类是从基类派生的,那么派生类也有基类的隐藏字段


  • 派生类是否共享基类字段?我的意思是为基类和派生类分配单独的内存块
  • 对象以包含指向其实际类型信息的指针的标题开头。该类型信息包括vtable,它可以计算出哪种方法实际上意味着什么。CLR在执行时使用该vtable调用重写的方法

    对象头之后是与对象关联的所有实例数据,包括基类字段和派生类字段。这一切都在一个地方——它不像派生类的实例也有对基类的“隐藏”实例的引用。我强烈怀疑基类字段是第一位的,因为基类中的方法仍然可以通过从对象“顶部”的偏移引用(在汇编中)相同的字段。。。但我面前没有任何东西可以证实这一点


    IIRC,杰夫·里克特(Jeff Richter)在某种程度上谈到了这一切——这是这类事情的一个很好的信息来源。

    你可以把对象想象成有“插槽”,可以在其中放入方法和字段。。。基类将有用于字段的插槽1、2、3,并且,比如说,一个方法有插槽4。如果创建派生类,新字段将添加另一个插槽(例如插槽5)

    这样,使用基类类型的变量仍然可以访问正确的字段,而不必担心差异。派生类的构造函数必须首先调用基类构造函数,即使您没有在代码中显式指定它

    如果slot-4方法是虚拟的,并且派生类重写了它,则将重写方法再次放入slot-4,如果隐藏它(通过
    new
    ),它将分配一个新的slot(因此只能通过派生类的变量调用它)

    我就是这么想的。这是一种简化的方法,但它有帮助。我想它可能是一个内存块,但话说回来,这是一个实现细节。


    (来源:)

    是的,派生类还将在内存中包含基类字段。杰弗里·里克特(Jeffrey Richter)通过C#在CLR第112页上说:

    然后,M3执行其代码来构造Manager对象。这将导致在托管堆中创建管理器类型的实例,即管理器对象,如图4-9所示。如您所见,管理器对象和所有对象一样具有类型对象指针和同步块索引此对象还包含必要的字节,用于将管理器类型定义的所有实例数据字段保存为管理器类型的任何基类(在本例中为Employee和object)定义的任何实例字段。(重点添加)

    还值得注意的是,会为任何基本类型创建一个单独的内存块。但仅为类型数据创建一个内存块(因此最多只能创建一次)。当您创建一个管理器对象(从Employee派生)时,CLR将确保堆上有一个管理器类型对象,以及一个员工类型对象

    1) 雷德蒙:微软出版社,2006年。
    ()

    第110-116页相关讨论。哇!感谢您的关心和花时间解释细节。我真的很感谢您。
    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");
    }
    
    -----------------
     Manager
    -----------------
    empID
    empName
    ssn
    branchID