您的位置:首页 > 其它

[你必须知道的.NET] 第十五回:继承本质论(转CNBlog)

2008-10-13 09:16 344 查看
本文将介绍以下内容:
  • 什么是继承?

  • 继承的实现本质

  1. 引言

  关于继承,你是否驾熟就轻,关于继承,你是否了如指掌。

  本文不讨论继承的基本概念,我们回归本质,从编译器运行的角度来揭示.NET继承中的运行本源,来发现子类对象是如何实现了对父类成员与方法的继承,以最为简陋的示例来揭示继承的实质,阐述继承机制是如何被执行的,这对于更好的理解继承,是必要且必然的。

  2. 分析

  下面首先以一个简单的动物继承体系为例,来进行说明:

Bird bird2 = new Chicken();


  这种情况下,bird2.ShowType应该返回什么值呢?而bird2.type有该是什么值呢?有两个原则,是.NET专门用于解决这一问题的:

  • 关注对象原则:调用子类还是父类的方法,取决于创建的对象是子类对象还是父类对象,而不是它的引用类型。例如Bird bird2 = new Chicken()时,我们关注的是其创建对象为Chicken类型,因此子类将继承父类的字段和方法,或者覆写父类的虚方法,而不用关注bird2的引 用类型是否为Bird。引用类型不同的区别决定了不同的对象在方法表中不同的访问权限。

注意

根据关注对象原则,那么下面的两种情况又该如何区别呢?

Bird bird2 = new Chicken();

Chicken chicken = new Chicken();

根据我们上文的分析,bird2对象和chicken对象在内存布局上是一样的,差别就在于其引用指针的类型不同:bird2为Bird类型指针, 而chicken为Chicken类型指针。以方法调用为例,不同的类型指针在虚拟方法表中有不同的附加信息作为标志来区别其访问的地址区域,称为 offset。不同类型的指针只能在其特定地址区域内进行执行,子类覆盖父类时会保证其访问地址区域的一致性,从而解决了不同的类型访问具有不同的访问权 限问题。

• 执行就近原则:对于同名字段或者方法,编译器是按照其顺序查找来引用的,也就是首先访问离它创建最近的字段或者方法,例如上例中的bird2,是Bird 类型,因此会首先访问Bird_type(注意编译器是不会重新命名的,在此是为区分起见),如果type类型设为public,则在此将返回 “Bird”值。这也就是为什么在对象创建时必须将字段按顺序排列,而父类要先于子类编译的原因了。

思考

1. 上面我们分析到bird2.type的值是“Bird”,那么bird2.ShowType()会显示什么值呢?答案是“Type is Chicken”,根据本文上面的分析,想想到底为什么?

2. 关于new关键字在虚方法动态调用中的阻断作用,也有了更明确的理论基础。在子类方法中,如果标记new关键字,则意味着隐藏基类实现,其实就是创建了与父类同名的另一个方法,在编译中这两个方法处于动态方法表的不同地址位置,父类方法排在前面,子类方法排在后面。

  4. 结论

  在.NET中,如果创建一个类,则该类总是在继承。这缘于.NET的面向对象特性,所有的类型都最终继承自共同的根System.Object 类。可见,继承是.NET运行机制的基础技术之一,一切皆为对象,一切皆于继承。本文从基础出发,深入本质探索本源,分析疑难比较鉴别。对于什么是继承这 个话题,希望每个人能从中寻求自己的答案,理解继承、关注封装、玩转多态是理解面向对象的起点,希望本文是这一旅程的起点。

                            ©2007 Anytao.com

转:http://kb.cnblogs.com/page/42333/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: