C# 继承、接口与多态
来源:互联网 发布:itunes怎么安装软件 编辑:程序博客网 时间:2024/04/30 05:07
C# 继承、接口与多态
我在这里想谈一谈在C#中的继承(继承于基类或接口)和多态(如方法的覆写)。继承和多态是面向对象编程中两个重要的特性,这种特性和编程语言本身是没多大关系的,因此我先会用非编程的思维来谈一谈我对它们的认识,然后再谈一谈它们在C#中的实现方法。
1、继承的含义
所谓继承,就是“站在巨人的肩膀上”进行扩展。例如,最开始的铅笔尾端是没有橡皮擦的,后来有个男孩在尾端装上了橡皮擦,铅笔的销量一路飙升,他也成了百万富翁,这说明好的灵感多么的重要!(偏题了啊喂!感兴趣的童鞋请戳:http://baike.baidu.com/view/1628703.htm)好吧,回归正题,这就是一个典型的继承。我们在做一个“橡皮头铅笔”时,不需要想如何做一支铅笔,而是拿来一支现成的铅笔,在它上面装上橡皮而已。继承可以帮助我们重用组件,继承是人类不断进步的源泉(貌似又偏题了!)。
2、多态的含义
从非编程的角度来看“多态”,可以理解成“不同的人执行相同的条例,却有不同的行为”。在编程的角度来看,是“不同的对象执行相同的方法,却有不同的行为”。怎么来理解呢,我可以打以下这个比方。
某学校的学生规范中有写道:“老师进教室时,学生坐好如下课前准备:安静坐好。此时值日生应该上讲台擦黑板,课代表收本科目作业。”教室里,除了老师外,其他的人都是学生(包括课代表和值日生),在执行这些行为的时候,课代表和值日生为什么不和规范中所提到的“学生”一样安静坐好呢?因为规范中还说到,他们有自己的职责:一个应当擦黑板,一个应当收作业。这就是多态,虽然学生们都要做好课前准备,但是却不全部相同。由“学生”派生出来的“课代表”要收作业,由“学生”派生出来的值日生要擦黑板,而“学生”这个“基类”的各个同学只需要安静坐好。他们都执行着相同的条例(做课前准备),却有不同的行为。
3、接口的含义
通俗地来打比方,我要开发一个多功能插线板,其中的插头孔要支持大陆标准、香港标准、英国标准和美国标准。我只需要把插线板按照标准挖出这4个孔就可以了,我就可以说,我这个插线板可以插大陆、香港、美国、英国的电源。至于插上去后怎么样,我不关心,我只关心,它可以插这些电源。再例如,我开发了一个新的电子产品,此产品要支持用USB来传数据,我就要预留一个USB接口,至于接上USB数据线之后怎么样,这个是以后的事情,总之它先要支持USB接口。
从程序的角度通俗的来理解接口,就是定义程序有这样的一种“兼容性”,而不去管接口内部是怎么实现的。因此,作为接口,它只包含定义,而不包含具体的实现,这也是它和抽象类的最大区别(抽象类中可以包含方法的实现)。
4、C#中的继承与多态
C#不像C++那样区分“共有继承"、"私有继承"。所有的继承均是共有的,也就是基类的所有成员的访问性在派生类中都不会变。并且,C#中只支持单一继承,但是可以继承多个接口。这个很容易理解,一辆高级汽车,它只继承于一个对象(一辆普通汽车),而不会同时继承于一辆汽车和一架飞机;但是它可以用很多个接口,如加油的接口和充电的接口。Java和C#的设计值发现多重继承在使用起来太蛋疼了,因此在他们的语言中去掉了这个特性。
类的访问性、成员定义方法我就不进行阐述了,因为这是很基本的东西。下面我主要来谈一谈抽象类、虚函数,它们是实现多态的重要部分。
有如下代码,定义了一个Creature类,Creature类派生了两个子类:Animal和Human。Creature类有一个抽象方法Eat。抽象方法是指,继承于本抽象类的派生类都必须自己实现这个方法。抽象方法只是一个声明,没有方法体,包含抽象方法的类一定要为抽象类。由于Eat是抽象方法,Human和Animal继承于抽象类Creature,因此它们都必须要实现自己的Eat方法。代码如下:
using System;namespace Demo{ public abstract class Creature { public abstract void Eat(); } public class Human : Creature { public override void Eat() { Console.WriteLine("用火先将食物烤熟再吃。"); } } public class Animal : Creature { public override void Eat() { Console.WriteLine("直接吞下肚子。"); } } public class Program { static void Main(string[] args) { Creature h = new Human(); Creature a = new Animal(); h.Eat(); a.Eat(); } }}
运行后,屏幕输出如下:
用火先将食物烤熟再吃。
直接吞下肚子。
显然,前者是执行h.Eat()的结果,后者是执行a.Eat()的结果。派生于同一个类的两个派生类,其Eat方法经过了重写表现出了不同的行为。需要注意的是,在覆写基类的抽象方法时,必须要使用override关键字,否则无法通过编译。
抽象类Creature是无法实例化的(无法用new Creature()来实例化),因为它还有一个方法Eat没有实现。如果我们想让Creature有个“默认”的Eat方法,应该怎么做呢?这个时候就需要利用虚函数了。
代码如下:
using System;namespace Demo{ public class Creature { public virtual void Eat() { Console.WriteLine("生物消化了食物。"); } } public class Human : Creature { public override void Eat() { Console.WriteLine("用火先将食物烤熟再吃。"); } } public class Animal : Creature { public override void Eat() { Console.WriteLine("直接吞下肚子。"); } } public class Program { static void Main(string[] args) { Creature h = new Human(); Creature a = new Animal(); Creature c = new Creature(); h.Eat(); a.Eat(); c.Eat(); } }}上例中,我们为Creature类添加了一个虚方法Eat。也就是说,如果Creature的派生类没有被覆写,它就调用基类的Eat。所谓被覆写,就是派生类中存在同名函数,且使用了关键字override。在之前提过的学生、课代表、值日生的例子中,代码如下所示:
using System;namespace Demo{ public class Student { public virtual void ClassBegin() { Console.WriteLine("安静坐好。"); } } public class StudentOnDuty : Student { public override void ClassBegin() { Console.WriteLine("擦黑板。"); } } public class Representative : Student { public override void ClassBegin() { Console.WriteLine("收作业。"); } } public class Program { static void Main(string[] args) { //定义学生 Student s = new Student(); //定义课代表 Student r = new Representative(); //定义值日生 Student d = new StudentOnDuty(); s.ClassBegin(); r.ClassBegin(); d.ClassBegin(); } }}
你可能会注意到,只有我们用基类的类型来定义一个派生类的对象时,才有多态的机制。多态有什么意义呢?举例来说,假设有一个方法,需要传入一个Student类,它可以调用Student类中的ClassBegin。如果没有多态,我们就要这样做:
public void WhenClassBegin(Student s){ s.ClassBegin();}public void WhenClassBegin(Representative s){ s.ClassBegin();}public void WhenClassBegin(StudentOnDuty s){ s.ClassBegin();}
如果再增加一个派生类,我们就要为WhenClassBegin多增加一个版本,这样做工作量巨大而且不易于维护!现在有了多态,有了虚函数,我们只需要这样来写:
public void WhenClassBegin(Student s){ s.ClassBegin();}
因为Student对象能知道,它究竟要调用哪个ClassBegin方法。
5、C#中的接口
C#中定义接口十分简单。接口中的方法不包含可访问性修饰符,也不包含方法体。如以下就是一个接口的声明和使用:
using System;namespace Demo{ public interface IEdible { void Eat(); } public class Program : IEdible { public static void Main(string[] args) { IEdible food = new Program(); food.Eat(); } public void Eat() { Console.WriteLine("Yummy!"); } }}
需要注意的是IEdible food = new Program()这句话的意思是,实例化一个继承了IEdible的对象。一定要注意,接口是不能实例化的,只能实例化一个具有某种接口的对象。如果Program没有继承IEdible,那么编译器就会报错。
这个就是我对继承、接口、多态的一些理解,这些概念广泛地运用在各种面向对象编程中,希望对大家有用。
- C# 继承、接口与多态
- C#基础-继承、多态与接口
- C#锐利体验 第十讲 接口、继承与多态
- C#中的继承与多态还有接口
- C#中的继承与多态还有接口
- 接口、继承与多态
- 重载与多态,接口与继承
- C#继承与多态
- C#继承与多态
- 《C#面向对象程序设计》新教案发布:《继承、接口与多态》和《委托及事件》
- 黑马程序员:C#基础篇(四)抽象类、接口、继承与多态
- C#接口与继承(1)
- C#虚基类继承与接口的区别
- C#虚基类继承与接口的区别
- C#接口与继承的区别
- C#虚基类继承与接口的区别
- 黑马程序员-继承、接口与多态
- java接口继承与多态
- iOS学习之UIPickerView控件的关联选择
- Java GridBagLayout
- ubuntu VPN
- XP进军中国,Linux奋起反击
- 学习是一件吃力的事情
- C# 继承、接口与多态
- mysql设置字符集
- cocos2d-x CCLayer滑动效果和自定义剪切区域功能实现_CCScroeView
- win8.1 下 vc6无法启动
- 解密回声消除技术之一
- Android Database 并行访问
- NGUI学习笔记(一)UIRoot
- 运行查询结果
- 【OpenCV入门教程之四】 ROI区域图像叠加&初级图像混合 全剖析