《C#语言程序设计》-李继武 彭德林-电子教案 第4章

上传人:E**** 文档编号:89399478 上传时间:2019-05-24 格式:PPT 页数:211 大小:571KB
返回 下载 相关 举报
《C#语言程序设计》-李继武 彭德林-电子教案 第4章_第1页
第1页 / 共211页
《C#语言程序设计》-李继武 彭德林-电子教案 第4章_第2页
第2页 / 共211页
《C#语言程序设计》-李继武 彭德林-电子教案 第4章_第3页
第3页 / 共211页
《C#语言程序设计》-李继武 彭德林-电子教案 第4章_第4页
第4页 / 共211页
《C#语言程序设计》-李继武 彭德林-电子教案 第4章_第5页
第5页 / 共211页
点击查看更多>>
资源描述

《《C#语言程序设计》-李继武 彭德林-电子教案 第4章》由会员分享,可在线阅读,更多相关《《C#语言程序设计》-李继武 彭德林-电子教案 第4章(211页珍藏版)》请在金锄头文库上搜索。

1、第4章 C#面向对象高级编程,前面介绍了面向对象程序设计的基本概念和应用。但是面向对象还包括很多其他重要的概念。本章将深入分析面向对象编程的概念,并详细说明利用工具进行面向对象程序设计的方法。,4.1 类的继承与多态,4.1.1 继承 1、概述 现实世界中的许多实体之间不是相互孤立的,它们往往具有共同的特征,也存在内在的差别。人们可以采用层次结构来描述这些实体之间的相似之处和不同之处。 为了用软件语言对现实世界中的层次结构进行模型化,面向对象的程序设计技术引入了继承的概念。一个类从另一个类派生出来时,派生类从基类那里继承特性。派生类也可以作为其它类的基类。从一个基类派生出来的多层类形成了类的层

2、次结构。 注意:C#中,派生类只能从一个类中继承。这是因为,在C+中,人们在大多数情况下不需要一个从多个类中派生的类。从多个基类中派生一个类,这往往会带来许多问题,从而抵消了这种灵活性带来的优势。,C#中,派生类从它的直接基类中继承成员:方法、域、属性、事件、索引指示器。除了构造函数和析构函数,派生类隐式地继承了直接基类的所有成员。,C#中,派生类从它的直接基类中继承成员:方法、域、属性、事件、索引指示器。除了构造函数和析构函数,派生类隐式地继承了直接基类的所有成员。 程序清单: using System; namespace ConsoleApplication1 class Vehicle

3、 /定义汽车类 int wheels; /公有成员:轮子个数 protected float weight; /保护成员:重量 public Vehicle(); public Vehicle(int w, float g) wheels=w; weight=g;, public void Speak() Console.WriteLine(“the w vehicle is speaking!“); class Car: Vehicle /定义轿车类:从汽车类中继承 int passengers;/私有成员:乘客数 public Car(int w, float g, int p) : ba

4、se(w,g) wheels=w; weight=g; passengers=p; ,Vehicle作为基类,体现了“汽车”这个实体具有的公共性质:汽车都有轮子和重量。 Car类继承了Vehicle的这些性质,并且添加了自身的特性:可以搭载乘客。,C#中的继承符合下列规则: (1)继承是可传递的。如果C从B中派生,B又从A中派生,那么C不仅继承了B中声明的成员,同样也继承了A中的成员。Object类作为所有类的基类。 (2)派生类应当是对基类的扩展。派生类可以添加新的成员,但不能除去己经继承的成员的定义。,(3)构造函数和析构函数不能被继承。除此以外的其它成员,不论对它们定义了怎样的访问方式,

5、都能被继承。基类中成员的访问方式只能决定派生类能否访问它们。,(4)派生类如果定义了与继承而来的成员同名的新成员,就可以覆盖己继承的成员。但这并不因为这派生类删除了这些成员,只是不能再访问这些成员。 (5)类可以定义虚方法、虚属性以及虚索引指示器,它的派生类能够重载这些成员,从而实现类可以展示出多态性。,2、覆盖,我们上面提到,类的成员声明中,可以声明与继承而来的成员同名的成员。这时我们称派生类的成员覆盖(hide)了基类的成员。这种情况下,编译器不会报告错误,但会给出一个警告。对派生类的成员使用new关键字,可以关闭这个警告。 前面汽车类的例子中,类Car继承了Vehicle的Speak()

6、方法。我们可以给Car类也声明一个Speak()方法,覆盖Vehicle中的Speak,见下面的代码。 程序清单:,using System; namespace ConsoleApplication1, class Vehicle/定义汽车类 public int wheels; /公有成员:轮子个数 protected float weight;/保护成员:重量 public Vehicle(); public Vehicle(int w, float g) ,wheels=w; weight=g;, public void Speak() Console.WriteLine(“the w

7、 vehicle is speaking!“); class Car:Vehicle /定义轿车类 int passengers;/私有成员:乘客数 public Car(int w, float g, int p) wheels=w; weight=g;,passengers=p;, new public void Speak() Console.WriteLine(“Di-di!“); 注意:如果在成员声明中加上了new关键字修饰,而该成员事实上并没有覆盖继承的成员,编译器将会给出警告。在个成员声明同时使用new和override则编译器会报告错误。,3、base保留字,base关键字主要

8、是为派生类调用基类成员提供一个简写的方法。我们先看一个例子程序代码: using System; namespace ConsoleApplication1 class A public void F() /F的具体执行代码 ,public int thisint nIndex, get set class B public void G() int x=base0; base.F(); ,类B从类A中继承,B的方法G中调用了A的方法F和索引指示器。方法F在进行编译时等价于:,public void G() int x=(A (this)0; (A (this).F(); 使用base关键字对

9、基类成员的访问格式为: base .标识符 base 表达式列表,4.1.2 多态,在面向对象的系统中,多态性是一个非常重要的概念,它允许客户对一个对象进行操作,由对象来完成一系列的动作,具体实现哪个动作、如何实现由系统负责解释。,4.1.2.1 C#中的多态,“多态性”一词最早用于生物学,指同一种族的生物体具有相同的特性。 在C#中,多态性的定义是:同一操作作用于不同的类的实例,不同的类将进行不同的解释,最后产生不同的执行结果。C#支持两种类型的多态性: (1)编译时的多态性 编译时的多态性是通过重载来实现的。我们在前面介绍了方法重载,都实现了编译时的多态性。 对于非虚的成员来说,系统在编译

10、时,根据传递的参数、返回的类型等信急决定实现何种操作。,(2)运行时的多态性,运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C#中,运行时的多态性通过虚成员实现。 编译时的多态性为我们提供了运行速度快的特点,而运行时的多态性则带来了高度灵活和抽象的特点。,4.1.2.2 虚方法,当类中的方法声明前加上了virtual修饰符,我们称之为虚方法,反之为非虚。使用了virtual修饰符后,不允许再有static, abstract,或override修饰符。,对于非虚的方法,无论被其所在类的实例调用,还是被这个类的派生类的实例调用,方法的执行方式不变。而对于虚方法,它的执行方式

11、可以被派生类改变,这种改变是通过方法的重载来实现的。,案例:虚方法与非虚方法的调用 目标:说明了虚方法与非虚方法的区别 步骤: 1、启动VS.NET,新建一个控制台应用程序,名称填写为“DifferentiateTest”,位置设置为“c:CSharpSampleschp4”。,2、在代码设计窗口中编辑Class1.cs。其中的代码编写如下:,using System; namespace DifferentiateTest class A public void F()Console.WriteLine(“A.F“); public virtual void G()Console.Write

12、Line(“A.G“); class B: A new public void F()Console.WriteLine(“B.F“); public override void G()Console.WriteLine(“B.G“); ,class Test, static void Main() B b=new B(); A a=b; a.F(); b.F(); a.G(); b.G(); ,3、按Ctrl + F5编译并运行该程序,效果如图5-2所示。,图 4-1 程序运行结果,例子中,A类提供了两个方法:非虚的F和虚方法G。类B则提供了一个新的非虚的方法F,从而覆盖了继承的F;类B同时

13、还重载了继承的方法G。 在本例中,方法a.G()实际调用了B.G,而不是A.G。这是因为编译时值为A,但运行时值为B,所以B完成了对方法的实际调用。,4.1.2.3 在派生类中对虚方法进行重载,先让我们回顾一下普通的方法重载。普通的方法重载指的是:类中两个以上的方法(包括隐藏的继承而来的方法),取的名字相同,只要使用的参数类型或者参数个数不同,编译器便知道在何种情况下应该调用哪个方法。,而对基类虚方法的重载是函数重载的另一种特殊形式。在派生类中重新定义此虚函数时,要求的是方法名称、返回值类型、参数表中的参数个数、类型、顺序都必须与基类中的虚函数完全一致。在派生类中声明对虚方法的重载,要求在声明

14、中加上override关键字,而且不能有new, static或virtual修饰符。,4.1.3 抽象和密封,1、抽象类 有时候,基类并不与具体的事物相联系,而是只表达一种抽象的概念,用以为它的派生类提供一个公共的界面。为此,C#中引入了抽象类(abstract class)的概念。,注意:C+程序员在这里最容易犯错误。C+中没有对抽象类进行直接声明的方法,而认为只要在类中定义了纯虚函数,这个类就是一个抽象类。纯虚函数的概念比较晦涩,直观上不容易为人们接受和掌握,因此C#抛弃了这一概念。,抽象类使用abstract修饰符,对抽象类的使用有以下几点规定: (1)抽象类只能作为其它类的基类,它不

15、能直接被实例化,而且对抽象类不能使用new操作符。抽象类如果含有抽象的变量或值,则它们要么是null类型,要么包含了对非抽象类的实例的引用。 (2)抽象类允许包含抽象成员,虽然这不是必须的。,(3)抽象类不能同时又是密封的。,如果一个非抽象类从抽象类中派生,则其必须通过重载来实现所有继承而来的抽象成员。请看下面的示例: using System; namespace ConsoleApplication1 abstract class A public abstract void F(); abstract class B: A public void G() ,class C: B publ

16、ic override void FD /F的具体实现代码 ,抽象类A提供了一个抽象方法F。类B从抽象类A中继承,并且又提供了一个方法G;因为B中并没有包含对F的实现,所以B也必须是抽象类。类C从类B中继承,类中重载了抽象方法F,并且提供了对F的具体实现,则类C允许是非抽象的。,2、抽象方法,由于抽象类本身表达的是抽象的概念,因此类中的许多方法并不一定要有具体的实现,而只是留出一个接日来作为派生类重载的界面。举一个简单的例子,“图形”这个类是抽象的,它的成员方法“计算图形面积”也就没有实际的意义。面积只对“图形”的派生类比如“圆”、“一角形”这些非抽象的概念才有效,那么我们就可以把基类“图形”的成员方法“计算面积”声明为抽象的,具体的实

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 高等教育 > 大学课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号