在继承和多态中的内存分配机制:
继承、封装和多态是面向对象的三大支柱要素,也是C#语言中最为重要的概念。在这里无意具体讲解他们的意义、使用方法等,只是想通过具体实例,从它们的内存分配,以期理解其运行机制,从而对继承和多态概念有深层次的理解。
这里节选Anytao的《你必须知道的.NET》之继承本质论中示例代码和演示图片,加以说明:
{
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);
}
}
当运行代码为:
{
public static void Main()
{
Bird bird = new Bird();
Chicken chicken = new Chicken();
}
}
由我们上文所论述的:自定义对象的内存分配机制,可知,其对应的内存分配图为:
从继承的方面:
我们可以得出如下结论:
1.即使是对同名的private类型字段type,当在子类中依然定义时,则在子类对象的字段中依然存在。而父类和其却将type字段都加上了Bird_type和Chicken_type加以区分;
2.Chicken方法表中,可以实现ShowColor方法,其依赖于属性Color。其是可以继承的,因为就其本质,它等价于在C++中的Get和Set函数(这里属性,包含get和set访问器);
然而从多态的方面:
然而如果使用这个语句,如果调用bird2.ShowType(),将会产生什么结果呢?
答案是:"Type is Chicken";
这就是多态的魅力!在这里它如何实现的呢?我们详细讲述一下它的实现方法:
1.对于Bird类型引用,他先查阅自己的Method Table 表,检测定位到标记为Virtual的方法或已经是Override的方法,然后从所指向具体的实例的TypeHandler指向的Method Table 中,查阅是否有被标记为override的对应函数,如果有则调用;如果没有,则向上一直追溯至System.Object(例如Object自带的几个方法Tostring()、Equals()等)为止;
2.Override的实现机理就是将子类的同名函数,覆盖掉父类的函数(因为:在初始化Chicken的方法表时是要按父类优先,子类最后的原则的,这样才能够实现"覆盖").然而预期相对应的New关键字(或默认不写时) 。它所做的,就是在子类中另写一个同名方法,用类型来标记(雷同于前述的字段同名情况)。这样同样是用上述调用语句,当父类检测自己的标记为Virtual的方法或已经是Override的方法,然后从所指向具体的实例的TypeHandler指向的Method Table 中,查阅是否有被标记为override的对应函数,如果有,并且,还存在同名的子类型标记的同名函数,则调用标记为本类(父类)的函数,从而没有实现覆盖;如果没有,则向上一直追溯至System.Object(例如Object自带的几个 方法Tostring()、Equals()等)为止;
综述之,实现继承和多态的内存分配机制的差距,以及具体的用Virtual和Override关键字的函数实现覆盖和重载 ,让我们看到内存在其中起到的巨大作用,页可以加深对继承和多态——面向对象中最重要的概念的理解,呵呵~
附:本文代码和演示图片摘自Anytao的《你必须知道的.NET》 一书,特此感谢。。。