C # - How does the CLR organize memory / reference during inheritance?
Suppose I have a piece of code like this: ( lightening target / not formed )
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");
}
Using the base keyword , I call the parent class constructor .
In this case, how is inheritance organized? I have some bad guesses as follows:
Since Manager is derived from Employee, the manager class is populated with (empID, empName, ssn)
-----------------
Manager
-----------------
empID
empName
ssn
branchID
step 1: calling the constructor: base ("1", "sam", "xxx")
Step 2: the constructor of the base class (Employee) populates the processed derived class (empID, empName, ssn)
Step 3: branchID is assigned by the derived class constructor
.......
My question
If the class is derived from a base class, does the derived class also have base class hidden fields?
Do derived classes share base class fields? I mean, a separate block of memory is allocated for the base class and the derived class?
source to share
(source: rvenables.com )
Yes, the derived class will also have the base class fields in memory. On CLR page 112 via C # Jeffrey Richter says:
"M3 then runs its code to create a Manager object. This results in an instance of type Manager being instantiated on the managed heap, a Manager object, as shown in Figure 4-9. As you can see, the Manager object - like all objects - has type object pointer and sync block index. This object also contains the bytes needed to store all instance data fields defined by the Manager type, as any instance fields defined by any base classes of the Manager type (in this case Employee and Object) . "(Emphasis added )
It is also worth noting that a separate memory block is created for any basic types. But ONLY for data of type (so only once, at most). When you create an object Manager (derived from Employee), CLR ensures that the heap is an object of type Manager, and the object type the Employee .
1) Richter, Jeffrey. CLR via C #. Redmond: Microsoft Press, 2006. ( Amazon Link )
source to share
An object starts with a header that includes a pointer to its actual type information. This type information includes a vtable to determine which method actually means which. The CLR uses this table at run time to call overridden methods.
Following the object header is all the instance data associated with the object, including base class fields and derived class fields. All in one place - it doesn't look like an instance of a derived class and has a reference to a "hidden" instance of the base class. I strongly suspect that the base class fields go first, since then the methods in the base class may still refer (in the assembly) to the same fields via offsets from the "top" of the object ... but I have nothing in front of me to confirm this is.
IIRC, Jeff Richter "CLR via C #" goes into all this in some detail - it's a great source of information for this sort of thing.
source to share
You can think of an object as having "slots" where you can put methods and fields ... the base class will have slots 1,2,3 for the fields and, say, the method has slot 4. If you create a derived class, the new field will add another slot (for example, slot 5).
This way, using a base class type variable still accesses the correct fields without worrying about differences. A derived class constructor must call the base class constructor first, even if you haven't explicitly specified it in your code.
If your slot-4-method is virtual and your derived class overrides it, you put the override method in slot 4 again, if you hide it (via new
) it allocates a new slot (so it can be called via a variable of the derived class).
It's good that I think about it. Kind of simplistic, but it helps. I think it might be one block of memory, but again, that's an implementation detail.
source to share