最近正在 看你必须知道的.NET这本书,下面是在看书过程中,记载的自己的一些感受和书中没有看到的,记下来供自己以后翻看:
07-10
page23 1.2章节 继承
ok,首先我们需要有对象定义,也就是class定义,根据书中的例子我们写出下面3个类的代码
public abstract class Animal
{
public abstract void ShowType();
public void Eat()
{
Console.WriteLine("Animal always eat!");
}
}
public class Bird:Animal
{
private string color;
public string Color
{
get { return color; }
set { color = value; }
}
private string type = "Bird";
public string Type
{
get { return type; }
}
public override void ShowType()
{
Console.WriteLine("Type is {0}", type);
}
}
public class Chicken:Bird
{
private string type = "Chicken";
public new string Type
{
get { return type; }
}
public override void ShowType()
{
Console.WriteLine("Type is {0}", type);
}
public void ShowColor()
{
Console.WriteLine("Color is {0}", Color);
}
}
当我们只是声明一个对象变量的时候:Bird bird ;仅仅是一个引用(指针),保存在线程的堆栈上,占用4Byte的内存空间,将用于保存Bird对象的有效地址,此时bird未指向任何有效的实例。
创建新对象 bird=new Bird();要说的主要在这里,通过F11进入Bird类内部会发现,程序对类内部的字段初始化,然后执行构造函数,这里private string color;只是声明变量没有赋值 ,设置断点不会执行到该语句,如果private string color = string.Empty;就会执行到这里
然后是书中重点提到的内容:
声明并创建两个对象:Bird bird2 = new Chicken();
Chicken chicken = new Chicken();
这时候bird2的字段或者属性读取的是Bird类的值,而方法是执行的Chicken的方法
书中的解释是:bird2对象和chicken对象在内存布局上是一样的,差别在于其引用指针的类型不同:brid2为Bird类型指针,而chicken为Chicken类型指针。以方法调用为例,不同的类型指针在虚拟方法表中有不同的附加信息作为标志来区别其访问的地址区域,称为offset。不用类型的指针只能在其特定的地址区域内执行,子类覆盖父类时会保证其访问地址区域的一致性,从而解决了不同的类型访问具有不同的访问权限问题。
执行就近原则:对于同名字段或者方法,编译器是按照其顺序查找来引用的,首先访问离他最近的字段或者方法,如上Type,这也就是为什么在对象创建时必须将字段按顺序排列,而父类要先于子类编译的原因了。