C#中的继承分为实现继承和接口继承,今天主要谈一下实现继承。
实现继承表示一个类型派生于另一个基类型,该类型拥有基类型的所有成员字段和函数。在实现继承中,派生类型的每个函数采用基类型的实现代码。——摘自《C#高级编程第六版》92页
为什么要使用类继承呢,举个小例子,假如说我们之前有个类叫Peoplo(人类),他具有身高、体重等属性,同时还具有吃饭、睡觉等方法,可是由于科技的进步人们又发明了机器人(Robot),它不但可以像人类那样具有身高、体重,还能够吃饭、睡觉外,它还具备人类所不具备的功能,例如机器人可以下潜到1000以下的深水中,如果没有继承,我们在定义Robot这个类的时候就得重复定义peoplo的成员和Robot所独特的成员,增加了我们的负担,使用继承就可以很好的解决这个问题,如下:
先看Peoplo类
1public class Peoplo
2{
3 public int stature { get; set; }//身高
4 public int avoirdupois { get; set; }//体重
5 public Peoplo()
6 {
7 //
8 //TODO: 在此处添加构造函数逻辑
9 //
10 }
11 public string dining()//吃饭
12 {
13 return "今天的红烧肉真好吃!";
14 }
15 public string dreamland()//睡觉
16 {
17 return "为什么不是席梦思的床垫呢?";
18 }
19}
该类定义了stature和avoirdupois两个属性,dining和dreanland两个方法。
再来看一下Robot类
1public class Robot:Peoplo
2{
3 public Robot()
4 {
5 //
6 //TODO: 在此处添加构造函数逻辑
7 //
8 }
9 public string dive()
10 {
11 return " 已经下潜到999米了,马上就要到1000米勒!";
12 }
13}
我想有必要先搞清楚什么是基类,Robot由Peoplo派生而来,那么Robot就是派生类而Peoplo就是基类,也可以这么说Robot 是Peoplo的派生类,Peoplo是Robot的基类。
下面我们使用Robot rb=new Robot(),这样我们得到了一个Robot类型的对象rb,那么rb都具备什么成员呢,没错,由于Robot继承了Peoplo类。所以它具备以下成员:stature和avoirdupois两个属性,dining和dreanland两个方法,还有就是自身的dive()方法。我们创建一个Default.aspx页面来输出结果验证一下。
1public partial class _4_Default : System.Web.UI.Page
2{
3 Robot rb = new Robot();
4
5 protected void Page_Load(object sender, EventArgs e)
6 {
7 Response.Write(rb.dining());
8 }
9}
运行结果:今天的红烧肉真好吃!
额的神啊,机器人怎么开始吃肉了啊,科技再进步机器人也无法吃肉啊,看来Peoplo类中的属性和方法不一定都适用于Robot啊,人类吃肉是用来补充能量,而机器人用什么补充能量呢,没错,电!看来我们有必要在Robot类中重新定义吃饭这个动作了,有人可能会说我们可以在定义一个RotboDining()方法,其实大可不必!我们只需改造一下Robot和Peoplo类就可以了,如下所示
1public class Peoplo
2{
3 public int stature { get; set; }//身高
4 public int avoirdupois { get; set; }//体重
5 public Peoplo()
6 {
7 //
8 //TODO: 在此处添加构造函数逻辑
9 //
10 }
11 public virtual string dining()//吃饭
12 {
13 return "今天的红烧肉真好吃!";
14 }
15 public string dreamland()//睡觉
16 {
17 return "为什么不是席梦思的床垫呢?";
18 }
19}
改造后的Peoplo和原来的没什么大的变化,只不过是dining()多了一个virtual关键字,它的作用是什么呢?稍后你就知道了。再来看一下改造后的Robot类,如下所示。
1public class Robot:Peoplo
2{
3 public Robot()
4 {
5 //
6 //TODO: 在此处添加构造函数逻辑
7 //
8 }
9 public string dive()
10 {
11 return " 已经下潜到999米了,马上就要到1000米勒!";
12 }
13 public override string dining()
14 {
15 return "别让俺干活,俺在充电中!";
16 }
17}
我们发现改造后的Robot类中多了一个public override string dining()方法,这个方法与基类Peoplo中的dinind()方法签名一模一样,而且前面还有一个关键字override,先别着急我们先来运行下Default.aspx页面看下运行结果,结果如下:
别让俺干活,俺在充电中!
怎么样现在Robot的dining()符合机器人的充电实际效果了吧。他是怎么实现的呢?
我们先来看下Robot的public override string dining(),这个方法与基类Peoplo中的dinind()方法签名一模一样,而且前面还有一个关键字override,这用声明方法的作用是重写基类中的dining()方法,这个声明关键就在于关键字override,他表示我要重写基类中的一个方法,那么要重写基类的哪个方法呢,这时候方法名dining()就派上用场了,他表示要重写基类的哪个方法,注意这个方法名一定要和基类中的方法签名一模一样(不光是方法名一样,参数的类型,数量,顺序要必须一致),如果这个方法签名与基类中被重写的方法签名不一致会发生错误。
那么是不是在派生类中能够将基类中的方法全部都能够重写呢,未必!这还要看看基类中的方法是不是可以被重写,怎么识别或设置基类中的方法能被重写呢,我们回过头来看看改造后的Peoplo类,前面我们说了,改造后的dining()多了一个virtual关键字,这个关键字的作用就是将此方法定义为虚方法,这样派生类就可以重写这个方法了,简单的说基类中的方法只有在用关键字virtual声明为虚方法时,派生类才能够重写这个方法。
那么当派生类重写了基类中的虚方法时,我们在调用基类这个方法时该方法会不会执行派生类中被重写的方法呢?我们来试验下,我们在default.aspx.cs中分别实例化一个Robot对象rb和Peoplo对象pl,然后分别调用这两个对象的dining()方法,代码如下:
1public partial class _4_Default : System.Web.UI.Page
2{
3 Robot rb = new Robot();
4 Peoplo pl = new Peoplo();
5 protected void Page_Load(object sender, EventArgs e)
6 {
7 Response.Write("Robot中的dining()方法:"+rb.dining()+"<br/>");
8 Response.Write("Peoplo中的dining()方法:"+pl.dining());
9 }
10}
运行结果:
Robot中的dining()方法:别让俺干活,俺在充电中!
Peoplo中的dining()方法:今天的红烧肉真好吃
试验结果表明:虽然在派生类Robot类中重写了基类peoplo中的dining()方法,但是这并没有影响到基类中的方法,也就是说派生类中重写的方法只在派生类中起作用,他并不能改变基类中被重写的方法。
关于类的继承就先谈到这里,说实话很简单,不过还有一个很重要也比较难以理解的关于实现继承的构造函数我们没有谈到,我会在下一篇随笔中简单的谈一下个人关于这方面的理解。
摘自红色黑客联盟(www.7747.net) 原文:http://www.7747.net/kf/201007/52319.html