博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C#面向对象三大特性之二:继承
阅读量:6113 次
发布时间:2019-06-21

本文共 5163 字,大约阅读时间需要 17 分钟。

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

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

调用子类:

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

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

4.继承的缺点

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

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

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

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

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

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

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

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

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

要点:

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

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

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

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

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

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

 

转载于:https://www.cnblogs.com/qinyi173/p/4685425.html

你可能感兴趣的文章
BZOJ 2190[SDOI2008]仪仗队
查看>>
图解SSH原理及两种登录方法
查看>>
[转载] 七龙珠第一部——第058话 魔境圣地
查看>>
【总结整理】JQuery基础学习---样式篇
查看>>
查询个人站点的文章、分类和标签查询
查看>>
基础知识:数字、字符串、列表 的类型及内置方法
查看>>
JSP的隐式对象
查看>>
P127、面试题20:顺时针打印矩阵
查看>>
JS图片跟着鼠标跑效果
查看>>
[SCOI2005][BZOJ 1084]最大子矩阵
查看>>
学习笔记之Data Visualization
查看>>
Leetcode 3. Longest Substring Without Repeating Characters
查看>>
【FJOI2015】金币换位问题
查看>>
数学之美系列二十 -- 自然语言处理的教父 马库斯
查看>>
Android实现自定义位置无标题Dialog
查看>>
面试总结
查看>>
Chrome浏览器播放HTML5音频没声音的解决方案
查看>>
easyui datagrid 行编辑功能
查看>>
类,对象与实例变量
查看>>
HDU 2818 (矢量并查集)
查看>>