搜公众号
推荐 原创 视频 Java开发 开发工具 Python开发 Kotlin开发 Ruby开发 .NET开发 服务器运维 开放平台 架构师 大数据 云计算 人工智能 开发语言 其它开发 iOS开发 前端开发 JavaScript开发 Android开发 PHP开发 数据库
Lambda在线 > 产品技术知与行 > 解读经典《C#高级编程》第七版 Page100-107.继承.Chapter4

解读经典《C#高级编程》第七版 Page100-107.继承.Chapter4

产品技术知与行 2019-02-09
举报

前言

本章节继续讲实现继承。


实现继承

密封类和密封方法

密封类和方法的概念很简单,就是为了不允许类和方法被继承和扩展。不允许扩展一般的原因有:

  • 如果类或者方法被扩展,可能会导致类库执行错误

  • 因为版权原因,不允许第三方随意扩展该类

.Net库有很多密封类,使用者不能随意扩展。我猜测这么做可能是因为设计者想保持框架的纯净性和单一性,即不希望使用者随意扩展而导致出现众多“分支框架”,最终的导致框架的碎片化(参考Andriod的碎片化)。 最典型的,string类型就是密封类。我们可以猜测扩展方法的出现(.Net3.5版本)就是因为对.Net框架密封类有扩展的需求,但是密封类无法继承,所以出一个扩展方法作为“补偿办法”,一定程度上解决了对基础框架的扩展问题。

 
   
   
 
  1. 密封类案例

  2. /// <summary>

  3. /// 密封类案例:不能被继承,其方法不能被override。这个类同时还是基类

  4. /// </summary>

  5. public sealed class SaUser

  6. {

  7.    public void Test()

  8.    {

  9.        //密封类方法不能有virtual关键字,因为virtual代表可override,这和密封类的概念矛盾了

  10.    }


  11.    /// <summary>

  12.    /// 此写法为非法,不同通过编译: 基类中不能定义密封方法

  13.    /// </summary>

  14.    public sealed override void Test2()

  15.    {

  16.        //Test2()不能定义sealed,也不能定义sealed override,都会导致编译异常。

  17.    }

  18. }


  19. 密封方法案例

  20. /// <summary>

  21. /// 普通基类

  22. /// </summary>

  23. public class SaUser2

  24. {

  25.    public virtual void Test()

  26.    {

  27.        //可扩展的方法

  28.    }

  29. }

  30. /// <summary>

  31. /// 派生类的密封方法

  32. /// </summary>

  33. public class SaUserChilid : SaUser2

  34. {

  35.    /// <summary>

  36.    /// 密封方法必须是重写的方法

  37.    /// </summary>

  38.    public sealed override void Test()

  39.    {

  40.        //密封方法必须同时有sealed和override关键字

  41.        base.Test();

  42.    }

  43. }

有趣的现象

如上代码,有个有趣的现象是,定义密封类只需要使用sealed关键字,而定义密封方法时,sealed必须和override配对使用。同时,在基类中也不能对方法实行密封。为什么会这样呢?我猜想,设计者的观点应该是:“所谓密封,应该是对一个原先处于“开放”状态下的类进行密封”。但对密封的这个限制,确实使得语言特性不够灵活。实际上,对基类的方法进行密封,虽然极少发生,但理论上还是有需求的。

派生类的构造函数

前面我们讲过了单个类的构造函数。我们知道构造函数是必须的,当我们没有类的构造函数时,系统会默认提供一个构造函数,因为类中字段的数据初始化是依赖于构造函数的。 当我们还要构造较为复杂的派生类时,其构造函数如何运行,就成为一个非常值得研究的问题。研究清楚了它,你才能用“合适”的办法完成派生类的初始化。派生类的构造函数的麻烦,来自于类的“多构造函数”,也就是构造函数的重载。 首先,我们要知道构造函数的原则:

  1. 每个类(基类,派生类)的构造函数都是必须的。

  2. 类的构造是自底向上来构造的,先构造基类,再逐级向上构建派生类。(为什么必须这样逐级构造,可以看原文章了解)

  3. 类的构造方法是可重载的(多构造函数)。

在以上原则下,当一个派生类要开始构造时,我们发现,关键要注意什么?是构造链不能断!在这点上编译器会智能判断,如果它发现构造链断了,会发生编译错误。我们可以看个例子,这个例子我以前的文章就贴过。

 
   
   
 
  1. /// <summary>

  2. /// 基类

  3. /// </summary>

  4. class Line

  5. {

  6.    private int thick;


  7.    /// <summary>

  8.    /// 基类构造方法:代号A

  9.    /// </summary>

  10.    Line()

  11.    {

  12.        thick = 1;

  13.    }

  14. }


  15. /// <summary>

  16. /// 派生类

  17. /// </summary>

  18. public class Rect

  19. {

  20.    private int width;

  21.    private int height;


  22.    /// <summary>

  23.    /// 构造方法:代号B

  24.    /// </summary>

  25.    /// <param name="length"></param>

  26.    Rect(int length)

  27.        :this(length, length)   //初始化器

  28.    {

  29.        //构造一个正方形

  30.    }


  31.    /// <summary>

  32.    /// 构造方法:代号C

  33.    /// </summary>

  34.    /// <param name="width"></param>

  35.    /// <param name="height"></param>

  36.    Rect(int width, int height)

  37.        :base()     //初始化器

  38.    {

  39.        //构造一个长方形

  40.        this.width = width;

  41.        this.height = height;

  42.    }

  43. }

我给代码中的构造方法都加了代号。以上的demo,我们可以分析得出,如果使用B方法来构造对象,它的构造链是:A->C->B。如果用C方法来构造对象,构造链是:A->C。构造链是清晰的,就没有问题。


修饰符

重申一下何为修饰符:应用于类型或者成员的关键字。

可见性修饰符

不能把类型定义为protected,private,protected interval。嵌套类除外,因为类成员可以使用访问限制性修饰符,而嵌套类是和类的成员同等级的。

其他修饰符

解读经典《C#高级编程》第七版 Page100-107.继承.Chapter4


讲完继承,下篇开始讲解接口。

觉得文章有意义的话,请动动手指,分享给朋友一起来共同学习进步。


扫描二维码关注



版权声明:本站内容全部来自于腾讯微信公众号,属第三方自助推荐收录。《解读经典《C#高级编程》第七版 Page100-107.继承.Chapter4》的版权归原作者「产品技术知与行」所有,文章言论观点不代表Lambda在线的观点, Lambda在线不承担任何法律责任。如需删除可联系QQ:516101458

文章来源: 阅读原文

相关阅读

关注产品技术知与行微信公众号

产品技术知与行微信公众号:HolyKnight17

产品技术知与行

手机扫描上方二维码即可关注产品技术知与行微信公众号

产品技术知与行最新文章

精品公众号随机推荐

举报