您的位置:知识库 »

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

作者: Anytao  来源: 博客园  发布时间: 2008-09-12 14:34  阅读: 4611 次  推荐: 2   原文链接   [收藏]  
[1] [你必须知道的.NET] 第十五回:继承本质论
[2] [你必须知道的.NET] 第十五回:继承本质论

系列文章导航:

[你必须知道的.NET] 开篇有益

[你必须知道的.NET] 第一回:恩怨情仇:is和as

[你必须知道的.NET] 第二回:对抽象编程:接口和抽象类

[你必须知道的.NET] 第三回:历史纠葛:特性和属性

[你必须知道的.NET] 第四回:后来居上:class和struct

[你必须知道的.NET] 第五回:深入浅出关键字---把new说透

[你必须知道的.NET] 第六回:深入浅出关键字---base和this

[你必须知道的.NET] 第七回:品味类型---从通用类型系统开始

[你必须知道的.NET] 第八回:品味类型---值类型与引用类型(上)-内存有理

[你必须知道的.NET] 第九回:品味类型---值类型与引用类型(中)-规则无边

[你必须知道的.NET] 第十回:品味类型---值类型与引用类型(下)-应用征途

[你必须知道的.NET] 第十一回:参数之惑---传递的艺术(上)

[你必须知道的.NET] 第十二回:参数之惑---传递的艺术(下)

[你必须知道的.NET] 第十三回:从Hello, world开始认识IL

[你必须知道的.NET] 第十四回:认识IL代码---从开始到现在

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

[你必须知道的.NET] 第十六回:深入浅出关键字---using全接触

[你必须知道的.NET] 第十七回:貌合神离:覆写和重载

[你必须知道的.NET] 第十八回:对象创建始末(上)

[你必须知道的.NET] 第十九回:对象创建始末(下)

[你必须知道的.NET]第二十回:学习方法论

[你必须知道的.NET]第二十一回:认识全面的null

[你必须知道的.NET]第二十二回:字符串驻留(上)---带着问题思考

[你必须知道的.NET]第三十二回,深入.NET 4.0之,Tuple一二


从我们的分析,和上面的对象创建过程可见,对继承的本质我们有了更明确的认识,对于以下的问题就有了清晰明白的答案:

 

  • 继承是可传递的,子类是对父类的扩展,必须继承父类方法,同时可以添加新方法。

  • 子类可以调用父类方法和字段,而父类不能调用子类方法和字段。

  • 虚方法如何实现覆写操作,使得父类指针可以指向子类对象成员。 

  • new关键字在虚方法继承中的阻断作用。

  • 你是否已经找到了理解继承、理解动态编译的不二法门。

  3. 思考

  通过上面的讲述与分析,我们基本上对.NET在编译期的实现原理有了大致的了解,但是还有以下的问题,一定会引起一定的疑惑,那就是:


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

[第1页][第2页]
2
0

热门文章

    最新文章

      最新新闻

        热门新闻