面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低了耦合。

但在实际应用中,有好多对象具有相同或者相似的属性,比如有一个对象 果树(FruitTree),它有成员属性叶子(Leaf),会开花(Flower),有树干(Stem),有树根(Root),它还会生长(Growth方法)。

有另一个对象苹果树(AppleTree)它也是果树,具有果树所有特性,那么我们在编程的时候,定义了一个苹果树对象,假如再有一个桔子树(OrangeTree)、桃树(PeachTree)呢,我们不能一直复制这个对象改名字实现吧?这里就要用到面向对象的第二个特性:继承。

1.什么是继承

上面的果树(FruitTree) 和桔树(OrangeTree)之间是一个“ is-a ”的关系,即我们可以说 “桔树是果树”。在面向对象编程中,我们把这种关系称为 “继承”,即桔树继承自果树。或者说,桔树类是果树类的派生类;也可以说果树是父类,桔树是子类。同样的苹果树也可以继承果树,那么苹果树也可以说是果树的子类。在这里我们发现一个类可以有多个派生类,也就是一个类可以被多个类继承.

继承相关的概念:

(1) 当一个类A能够获取另一个类B中所有非私有的数据和操作的定义作为自己的部分或全部成分时,就称这两个类之间具有继承关系。

(2) 被继承的类B称为父类或基类,继承了父类的类A称为子类或派生类.

2.继承的特点

上面的例子,假如苹果树继承自果树,那么苹果树除了具有果树所有的属性(叶子,根、花)和方法(生长)之外,苹果树还有自己特有的一些属性,比如有自己的果实苹果(Apple); 同样桃树有自己的果实桃子(Peach),因此继承的子类可以有自己独有的成员(属性或方法等)。

特点一:派生类除了继承父类的特性外,还可以有自己独有特性

上面说到的父类果树(FruitTree)除了有叶子、根、花这些公有的成员之外,也可以有自己的私有成员,比如种类(落叶果树、常绿果树),而“种类”这个成员,并不是它的子类苹果树(AppleTree)和桔树(OrangeTree)所具有的,因此是私有成员,子类继承父类后,并不能拥有父类的私有成员。

特点二:子类不能拥有父类的私有成员

还是上面的例子,假如果树有一个公有方法生长(Growth),它有两个子类桃树和苹果树,那么子类也同时拥有生长这个方法,但是桃树和苹果树的生长过程是不同的,我们可以修改这个方法以适应不同种类果树的生长。

特点三:子类可以以自己的方式实现父类的功能(即方法重写)

3.继承的实现

通过上面的例子,我们已经对继承很熟悉了,抛开概念。简单的说,继承一词本就来源于生活,有财产继承,精神继承。面向对象编程只不过就是把这些概念抽象化而已,通俗来说就是“苹果树是一颗果树”

代码实现上面的例子

  1. /// <summary>
  2. /// 果树类
  3. /// </summary>
  4. class FruitTree
  5. {
  6. /// <summary>
  7. /// 名称
  8. /// 说明:修饰符 protected 保护访问。只限于本类和子类访问,实例不能访问。
  9. /// </summary>
  10. protected string name;
  11. /// <summary>
  12. /// 构造函数
  13. /// </summary>
  14. public FruitTree()
  15. {
  16. this.name = "无名";
  17. }
  18. /// <summary>
  19. /// 构造函数二
  20. /// </summary>
  21. /// <param name="name"></param>
  22. public FruitTree(string name)
  23. {
  24. this.name = name;
  25. }
  26. object _leaf;
  27. object _root;
  28. object _flower;
  29. string _type;
  30. /// <summary>
  31. /// 叶子(公有属性)
  32. /// </summary>
  33. public object leaf
  34. {
  35. get { return _leaf; }
  36. set { _leaf = value; }
  37. }
  38. /// <summary>
  39. /// 根(公有属性)
  40. /// </summary>
  41. public object root
  42. {
  43. get { return _root; }
  44. set { _root = value; }
  45. }
  46. /// <summary>
  47. /// 花(公有属性)
  48. /// </summary>
  49. public object flower
  50. {
  51. get { return _flower; }
  52. set { _flower = value; }
  53. }
  54. /// <summary>
  55. /// 类别(不定义修饰符,默认为私有)
  56. /// </summary>
  57. string type
  58. {
  59. get { return _type; }
  60. set { _type = value; }
  61. }
  62.  
  63. }
  64.  
  65. /// <summary>
  66. /// 苹果树类
  67. /// 继承自:果树类
  68. /// </summary>
  69. class AppleTree:FruitTree
  70. {
  71. string _myName;
  72. /// <summary>
  73. /// 构造函数
  74. /// 说明:子类调用父类同样的构造函数,需要使用 :base()
  75. /// </summary>
  76. public AppleTree():base()
  77. {
  78. }
  79. /// <summary>
  80. /// 构造函数二
  81. /// 说明:子类调用父类同样的构造函数,需要使用 :base(name)
  82. /// </summary>
  83. /// <param name="name"></param>
  84. public AppleTree(string name):base(name)
  85. {
  86. _myName = name;
  87. }
  88.  
  89. /// <summary>
  90. /// 返回果实的名字
  91. /// </summary>
  92. /// <returns></returns>
  93. public string MyFruitName()
  94. {
  95. return "我是:" + _myName + ";我的果实叫:苹果";
  96. }
  97. }
  98. /// <summary>
  99. /// 桔树类
  100. /// 继承自:果树类
  101. /// </summary>
  102. class OrangeTree : FruitTree
  103. {
  104. string _myName;
  105. /// <summary>
  106. /// 构造函数
  107. /// 说明:子类调用父类同样的构造函数,需要使用 :base()
  108. /// </summary>
  109. public OrangeTree(): base()
  110. {
  111. }
  112. /// <summary>
  113. /// 构造函数二
  114. /// 说明:子类调用父类同样的构造函数,需要使用 :base(name)
  115. /// </summary>
  116. /// <param name="name"></param>
  117. public OrangeTree(string name): base(name)
  118. {
  119. _myName = name;
  120. }
  121.  
  122. /// <summary>
  123. /// 返回果实的名字
  124. /// </summary>
  125. /// <returns></returns>
  126. public string MyFruitName()
  127. {
  128. return "我是:"+_myName+";我的果实叫:桔子";
  129. }
  130. }

调用子类:

  1. //调用子类
  2. AppleTree appleTree = new AppleTree("苹果树");
  3. string myName = appleTree.MyFruitName();
  4. //返回结果为:我是:苹果树;我的果实叫:苹果
  1. //调用子类
  2. OrangeTree orangeTree = new OrangeTree("桔子树");
  3. string myName = orangeTree. MyFruitName ();
  4. //返回结果为:我是:桔子树;我的果实叫:桔子

通这段代码,我们可以看到有了基类果树,那么我们再有几百种树,只需要一个继承就可以了,对于子类AppleTree.MyFruitName()返回名字这个方法,在不同子类中可以特有,就是继承的特点,可以增加特有成员。虽然对于独有特点需要在每个子类中单独定义,但是共享父类成员已经让我们省去不少工作量了,最重要的程序的结构更加清晰、易于维护了。

4.继承的缺点

看到这个标题,小伙伴们也许很惊讶,既然说了这么多面向对象继承特性的好处,原来还有缺点。当然,世界上没有完美的东西,继承也是。

 缺点一:父类变化,子类不得不变;

   缺点二:继承破坏了包装,父类的细节暴露给了子类。

前一节说了封装的独立特性,是减少了耦合性,而继承其为了实现复用却增加了耦合性。

说到这里小伙伴们纠结了,那么到底要不要使用继承,答案是肯定的,它的优点和光芒掩盖了缺点,也就是说好处更多一些。这里说明它的缺点,就是提醒我们在使用过程中尽量避免它的缺点所带来的后果。

那么要如何才能很好的使用继承呢?我们应该注意这么几点:

a.当两个对象间是“is a”关系时,可以使用继承(比如苹果树是树);b.当两个对象是“has a”关系时,不宜使用继承(比如手是人的一部分,不能让手继承人);

对于继承的优缺点,我们记住一点:要合理使用继承,才能发挥最佳效果,而不是盲目使用。

作为面向对象的三大特性之一:继承,可以说是学好面向对象编程的重中之重。

要点:

1:父类中的私有成员,派生类是绝不能访问;

2:C#要求一个类只能有一个直接基类;

3:被“sealed”关键字修饰的类将不能被继承;

4:被“protected”修饰的成员或者数据可以直接被派生类访问,属于“可以在家族里分享的秘密”。

5:善用“base”关键字,显示调用合适的自定义基类构造函数而不是使用默认构造函数。

6:继承需要合理使用才能发挥最佳效果,一般情况下适用于“is a”关系,不适用“has a”关系。

C#面向对象三大特性之二:继承的更多相关文章

  1. python 面向对象三大特性(封装 多态 继承)

    今天我们来学习一种新的编程方式:面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)注:Java和C#来说只支持面向对象编程,而python比较灵活即支持面 ...

  2. 面向对象的三大特性之二——继承(含super的使用)

    1.继承的语法:class 子类 extends 父类 例1: class Person { int age; String name; public void print1() { System.o ...

  3. JAVA三大特性之二——继承

    很多人在学习了JAVA以后,都会了解这个概念,而且继承也会在以后的开发中经常用到,但对于JAVA的继承特性,很多人都了解的不够深入,不够完整,当然这其中包括我,所以我就想抽点时间来整理一下JAVA继承 ...

  4. Python面向对象三大特性(封装、继承、多态)

    封装 类中把某些属性和方法隐藏起来,或者定义为私有,只在类的内部使用,在类的外部无法访问,或者留下少量的接口(函数)供外部访问:从上一篇文章中的私有属性与私有方法中的代码体现了该特性. class m ...

  5. [.net 面向对象编程基础] (12) 面向对象三大特性——继承

    [.net 面向对象编程基础] (12) 面向对象三大特性——继承 上节我们说了面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低 ...

  6. JAVA基础——面向对象三大特性:封装、继承、多态

    JAVA面向对象三大特性详解 一.封装 1.概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 2.好处: 只能通过规定的方法访问数据. ...

  7. python学习-64 面向对象三大特性----继承1

    面向对象三大特性 1.三大特性? 继承,多态,封装 2.什么是继承? 类的继承和现实生活中的父与子,继承关系是一样的,父类为基类. python中的类继承分为:单继承和多继承 3.举例说明 class ...

  8. 面向对象编程(九)——面向对象三大特性之继承以及重写、Object类的介绍

    面向对象三大特性 面向对象三大特征:继承 :封装/隐藏 :多态(为了适应需求的多种变化,使代码变得更加通用!) 封装:主要实现了隐藏细节,对用户提供访问接口,无需关心方法的具体实现. 继承:很好的实现 ...

  9. Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态)

    Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态) 1.面向对象的三大特性: (1)继承 ​ 继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可以 ...

随机推荐

  1. ELK的使用

    首先安装jdk,我这里使用open-jdk yum list all | grep jdk yum -y install java-1.8.0-openjdk-devel, java-1.8.0-op ...

  2. matlab函数之imresize()

    B = imresize(A,scale) B = imresize(A,scale) 返回图像 B,它是将 A 的长宽大小缩放 scale 倍之后的图像.输入图像 A 可以是灰度.RGB 或二值图像 ...

  3. Linux课程---10、权限管理(权限有哪几种)

    Linux课程---10.权限管理(权限有哪几种) 一.总结 一句话总结: r 读 w 写 x 执行 1.drwxr-x---  2 root root  4096 Jan 20 19:39 mnt ...

  4. 分享知识-快乐自己:Liunx-大数据(Hadoop)初始化环境搭建

    大数据初始化环境搭建: 一):大数据(hadoop)初始化环境搭建 二):大数据(hadoop)环境搭建 三):运行wordcount案例 四):揭秘HDFS 五):揭秘MapReduce 六):揭秘 ...

  5. Atom插件及使用

    Atom比较好用的编辑工具之一,之前用过 HBuilder 和 Sublime Text ,个人感觉HBuider适合初级人们的人用. Atom好处之一是他的packages管理安装非常方便,你也可以 ...

  6. python中的生成器(generator)总结

    1.实现generator的两种方式 python中的generator保存的是算法,真正需要计算出值的时候才会去往下计算出值.它是一种惰性计算(lazy evaluation). 要创建一个gene ...

  7. 利用bootsrap控件 实现文件上传功能

    源代码实例:https://github.com/kartik-v/bootstrap-fileinput 一.jsp页面 <%@ page language="java" ...

  8. Arc066_E Addition and Subtraction Hard

    传送门 题目大意 给定一个加减法的表达式,让你任意的添加合法的括号对,使的表达式最大. 题解 考虑到任意左括号一定加在减号右边,那么对于第一个左括号,与该左括号相邻的只含有加号的子序列的贡献一定为负, ...

  9. ACM学习历程—BestCoder Round #75

    1001:King's Cake(数论) http://acm.hdu.edu.cn/showproblem.php?pid=5640 这题有点辗转相除的意思.基本没有什么坑点. 代码: #inclu ...

  10. ACM学习历程—HDU1695 GCD(容斥原理 || 莫比乌斯)

    Description Given 5 integers: a, b, c, d, k, you're to find x in a...b, y in c...d that GCD(x, y) = ...