收藏 分享(赏)

第7章 继承和接口设计.ppt

上传人:sjmd695 文档编号:10201068 上传时间:2019-10-18 格式:PPT 页数:60 大小:269KB
下载 相关 举报
第7章 继承和接口设计.ppt_第1页
第1页 / 共60页
第7章 继承和接口设计.ppt_第2页
第2页 / 共60页
第7章 继承和接口设计.ppt_第3页
第3页 / 共60页
第7章 继承和接口设计.ppt_第4页
第4页 / 共60页
第7章 继承和接口设计.ppt_第5页
第5页 / 共60页
点击查看更多>>
资源描述

1、第7章 继承和接口设计,7.1继 承 7.2 多态性 7.3 抽象类 7.4 接口 7.5 接口在集合排序中的应用 7.6 泛型编程,7.1.1什么是继承一个类从另一个类派生出来时,称之为派生类或子类,被派生的类称为基类或父类。派生类从基类那里继承特性,派生类也可以作为其他类的基类,从一个基类派生出来的多层类形成了类的层次结构。,7.1 继 承,C#中只允许单继承,即一个派生类只能有一个基类。C#中继承是可传递的,如果C从B派生,B从A派生,那么C不仅继承B的成员,还继承A的成员。C#中派生类可添加新成员,但不能删除基类的成员。C#中派生类不能继承基类的构造函数和析构函数,但能继承基类的属性。

2、C#中派生类可隐藏基类的同名成员,如果在派生类可以隐藏了基类的同名成员,基类该成员在派生类中就不能被直接访问,只能通过“base.基类方法名”来访问。C#中派生类对象也是基类的对象,但基类对象却不一定是基派生类的对象。也就是说,基类的引用变量可以引用基派生类对象,而派生类的引用变量不可以引用基类对象。,C#中的继承具有以下特点:,7.1.2 派生类的声明派生类的声明格式如下:类修饰符 class 派生类:基类;C#中派生类可以从它的基类中继承字段、属性、方法、事件、索引器等。实际上除了构造函数和析构函数,派生类隐式地继承了基类的所有成员。,class A private int n; /私有字

3、段protected int m; /保护的字段public void afun() /公有方法/方法的代码 class B : A private int x; /私有字段public void bfun() /公有方法/方法的代码 ,从中看出Base_fun()方法在B类中不用重写,因为B类继承了A类,所以可以不用重写A类中的Base_fun()方法,就可以被B类调用。,在主函数中包含以下代码:B b = new B(); /定义对象并实例化b.afun();,7.1.3 基类成员的可访问性派生类将获取基类的所有非私有数据和行为。如果希望在派生类中隐藏某些基类的成员,可以在基类中将这些成员

4、设为private访问成员。,7.1.4 按次序调用构造函数和析构函数1. 调用默认构造函数的次序如果类是从一个基类派生出来的,那么在调用这个派生类的默认构造函数之前会调用基类的默认构造函数。调用的次序将从最远的基类开始。,class A /基类 public A() Console.WriteLine(“调用类A的构造函数“); class B : A /从A派生类B public B() Console.WriteLine(“调用类B的构造函数“); class C:B /从B派生类C public C() Console.WriteLine(“调用类C的构造函数“); 在主函数中执行以下

5、语句: C b=new C(); /定义对象并实例化 运行结果如下: 调用类A的构造函数 调用类B的构造函数 调用类C的构造函数,2. 调用默认析构函数的次序当销毁对象时,它会按照相反的顺序来调用析构函数。首先调用派生类的析构函数,然后是最近基类的析构函数,最后才调用那个最远的析构函数。,class A /基类 A() Console.WriteLine(“调用类A的析构函数“); class B : A /从A派生类B B() Console.WriteLine(“调用类B的析构函数“); class C:B /从B派生类C C() Console.WriteLine(“调用类C的析构函数“

6、); 在主函数中执行语句C b=new C();其运行结果如下: 调用类C的析构函数 调用类B的析构函数 调用类A的析构函数,3. 调用重载构造函数的次序调用基类的重载构造函数需使用base关键字。base关键字主要是为派生类调用基类成员提供一个简写的方法,可以在子类中使用base关键字访问的基类成员。调用基类中重载构造函数的方法是将派生类的重载构造函数作如下设计:public 派生类名(参数列表1):base(参数列表2) 其中,“参数列表2”和“参数列表1”存在对应关系。同样,在通过“参数列表1”创建派生类的实例对象时,先以“参数列表2”调用基类的构造函数,再调用派生类的构造函数。,【例7

7、.1】 分析以下程序的运行结果。,using System; namespace Proj7_1 class A private int x;public A() Console.WriteLine(“调用类A的构造函数“);public A(int x1) x = x1; Console.WriteLine(“调用类A的重载构造函数“); A() Console.WriteLine(“A:x=0“, x); class B : A private int y;public B() Console.WriteLine(“调用类B的构造函数“); public B(int x1,int y1):

8、base(x1) y = y1; Console.WriteLine(“调用类B的重载构造函数“); B() Console.WriteLine(“B:y=0“, y); ,class C:B private int z;public C() Console.WriteLine(“调用类C的构造函数“); public C(int x1,int y1,int z1):base(x1,y1) z = z1; Console.WriteLine(“调用类C的重载构造函数“); C() Console.WriteLine(“C:z=0“, z); class Program static void

9、Main(string args)C c=new C(1,2,3);,7.1.5 使用sealed修饰符来禁止继承C#中提供了sealed关键字用来禁止继承。要禁止继承一个类,只需要在声明类时加上sealed关键字就可以了,这样的类称为密封类。例如:sealed class 类名 这样就不能从该类派生任何子类。,7.2.1 什么是多态性面向对象程序设计中的多态性是一个重要的概念。所谓多态性,就是同一签名具有不同的表现行为,运算符重载和函数重载都属于多态性的表现形式。,7.2 多态性,7.2.2 隐藏基类方法当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。若要更改基类的数据和行为

10、,有两种选择:,方法1:使用新的派生成员替换基成员 方法2:重写虚拟的基成员。,方法1示例:在使用新的派生方法替换基方法时应使用new关键字。例如:class A public void fun()Console.WriteLine(“A“);class B:A new public void fun() /隐藏基类方法funConsole.WriteLine(“B“); 在主函数中执行以下语句:B b=new B();b.fun(); 运行结果如下:B,7.2.3 重写重写是指在子类中编写有相同名称和参数的方法。重写和重载的区别:后者是指编写(在同一个类中)具有相同的名称,却有不同的参数的方

11、法。也就是说,重写是指子类中的方法与基类中的方法具有相同的签名,而重载方法具有不同的签名。,1. virtual关键字virtual关键字用于修饰方法、属性、索引器或事件声明,并且允许在派生类中重写这些对象。例如,以下定义了一个虚拟方法并可被任何继承它的类重写:public virtual double Area() return x * y;调用虚方法时,首先调用派生类中的该重写成员,如果没有派生类重写该成员,则它可能是原始成员。注意:默认情况下,方法是非虚拟的,不能重写非虚方法。virtual修饰符不能与static、abstract和override修饰符一起使用。在静态属性上使用vir

12、tual修饰符是错误的。,2. 重写方法override方法提供从基类继承的成员的新实现。通过override声明重写的方法称为重写基方法。重写的基方法必须与override方法具有相同的签名。注意:不能重写非虚方法或静态方法。重写的基方法必须是virtual、abstract或override的。,【例7.2】 分析以下程序的运行结果。,using System; namespace Proj7_2 class Student protected int no; /学号protected string name; /姓名protected string tname; /班主任或指导教师pub

13、lic void setdata(int no1, string name1,string tname1)no = no1; name = name1;tname=tname1;public virtual void dispdata() /虚方法 Console.WriteLine(“本科生 学号:0 姓名:1 班 主 任:2“,no,name,tname);,class Graduate : Student public override void dispdata() /重写方法 Console.WriteLine(“研究生 学号:0 姓名:1 指导教师:2“, no, name, tn

14、ame);class Program static void Main(string args) Student s = new Student();s.setdata(101, “王华“,“李量“);s.dispdata();Graduate g = new Graduate();g.setdata(201,“张华“,“陈军“);g.dispdata(); ,【例7.3】 设计一个控制台应用程序,采用虚方法求长方形、圆、圆球体和圆柱体的面积或表面积。,using System; namespace Proj7_3 public class Rectangle /长方形类 public con

15、st double PI = Math.PI;protected double x, y;public Rectangle() public Rectangle(double x1, double y1)x = x1;y = y1;public virtual double Area() /求面积return x * y;,public class Circle : Rectangle /圆类 public Circle(double r): base(r, 0) public override double Area() /求面积return PI * x * x;class Sphere

16、: Rectangle /圆球体类 public Sphere(double r): base(r, 0) public override double Area() /求面积return 4 * PI * x * x;class Cylinder : Rectangle /圆柱体类 public Cylinder(double r, double h): base(r, h) public override double Area() /求面积return 2 * PI * x * x + 2 * PI * x * y;,class Program static void Main(stri

17、ng args) double x = 2.4, y = 5.6;double r = 3.0, h = 5.0;Rectangle t = new Rectangle(x,y);Rectangle c = new Circle(r);Rectangle s = new Sphere(r);Rectangle l = new Cylinder(r, h);Console.WriteLine(“长为0,宽为1的长方形面积=2:F2“,x,y,t.Area();Console.WriteLine(“ 半径为0的圆面积=1:F2“,r,c.Area();Console.WriteLine(“ 半径为

18、0的圆球体表面积=1:F2“,r,s.Area();Console.WriteLine(“半径为0,高度为1的圆柱体表面积=2:F2“, r,h,l.Area(); ,7.3 抽象类,7.3.1 什么是抽象类在类声明中使用abstract修饰符的类称为抽象类。抽象类具有以下特点:抽象类不能实例化。抽象类可以包含抽象方法和抽象访问器。抽象类中可以存在非抽象的方法。不能用sealed修饰符修改抽象类,这也意味着抽象类不能被继承。从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实现。抽象类可以被抽象类所继承,结果仍是抽象类。,7.3.2 抽象方法在方法声明中使用abstract修饰符以

19、指示方法不包含实现的,即为抽象方法。抽象方法具有以下特性:,声明一个抽象方法使用abstract关键字。抽象方法是隐式的虚方法。只允许在抽象类中使用抽象方法声明。一个类中可以包含一个或多个抽象方法。因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号。抽象方法实现由一个重写方法提供,此重写方法是非抽象类的成员。实现抽象类用“:”,实现抽象方法用override关键字。在抽象方法声明中使用static或virtual修饰符是错误的。抽象方法被实现后,不能更改修饰符。,【例7.4】 分析以下程序的运行结果。,using System; namespa

20、ce Proj7_4 abstract class A /抽象类声明abstract public int fun(); /抽象方法声明class B : A int x, y;public B(int x1, int y1) /抽象方法实现x = x1; y = y1;public override int fun()return x * y;,class Program static void Main(string args) B b = new B(2, 3);Console.WriteLine(“0“, b.fun();,6,7.3.3 抽象属性除了在声明和调用语法上不同外,抽象属性

21、的行为与抽象方法类似,另外,抽象属性具有如下特性:,在静态属性上使用abstract修饰符是错误的。在派生类中,通过包括使用override修饰符的属性声明,可以重写抽象的继承属性。抽象属性声明不提供属性访问器的实现,它只声明该类支持属性,而将访问器实现留给其派生类。,【例7.5】 分析以下程序的运行结果。,using System; namespace Proj7_5 abstract class A /抽象类声明 protected int x = 2;protected int y = 3;public abstract void fun(); /抽象方法声明public abstrac

22、t int px get;set; /抽象属性声明public abstract int py get; /抽象属性声明,class B : A public override void fun() /抽象方法实现 x+; y+; public override int px /抽象属性实现 set x = value; get return x + 10; public override int py /抽象属性实现 get return y + 10; class Program static void Main(string args) B b = new B();b.px = 5;b.

23、fun();Console.WriteLine(“x=0, y=1“, b.px, b.py); ,x=16,y=14,7.4 接口,7.4.1 什么是接口接口是类之间交互内容的一个抽象,把类之间需要交互的内容抽象出来定义成接口,可以更好的控制类之间的逻辑交互。接口具有下列特性:,接口类似于抽象基类。继承接口的任何非抽象类型都必须实现接口的所有成员。不能直接实例化接口。接口可以包含事件、索引器、方法和属性。接口不包含方法的实现。类和结构可从多个接口继承。接口自身可从多个接口继承。,接口只包含成员定义,不包含成员的实现,成员的实现需要在继承的类或者结构中实现。接口的成员包括方法、属性、索引器和事

24、件,但接口不包含字段。,7.4.2 接口的定义 1. 声明接口一个接口声明属于一个类型说明,其一般语法格式如下:接口修饰符 interface 接口名:父接口列表/接口成员定义体其中,接口修饰符可以是new、public、protected、internal和private。new修饰符是在嵌套接口中唯一被允许存在的修饰符,表示用相同的名称隐藏一个继承的成员。,2. 接口的继承接口可以从零个或多个接口中继承。当一个接口从多个接口中继承时,用“:”后跟被继承的接口名称,这多个接口之间用“,”号分隔。被继承的接口应该是可以被访问的,即不能从internal或internal类型的接口继承。对一个接

25、口的继承也就继承了接口的所有成员。例如:public interface Ia /接口Ia声明void mymethod1();public interface Ib /接口Ib声明int mymethod2(int x);public interface Ic : Ia, Ib /接口Ic从Ia和Ib继承,7.4.3 接口的成员 接口可以声明零个或多个成员。一个接口的成员不止包括自身声明的成员,还包括从父接口继承的成员。所有接口成员默认都是公有的,接口成员声明中包含任何修饰符都是错误的。 1. 接口方法成员语法格式:返回类型 方法名(参数表); 2. 接口属性成员语法格式:返回类型 属性名g

26、et; 或 set;例如,以下声明一个接口Ia,其中接口属性x为只读的,y为可读可写的,z为只写的:public interface Ia int x get;int y set;get;int z set;,3. 接口索引器成员 语法格式:数据类型 this索引参数表get; 或set; 例如:public interface Ia string thisint indexget;set; 4. 接口事件成员 语法格式:event 代表名 事件名; 例如:public delegate void mydelegate(); /声明委托类型public interface Iaevent my

27、delegate myevent;,7.4.4 接口的实现 接口的实现分为隐式实现和显式实现。如果类或者结构要实现的是单个接口,可以使用隐式实现,如果类或者结构继承了多个接口,那么接口中相同名称成员就要显式实现。显式实现是通过使用接口的完全限定名来实现接口成员的。 接口实现的语法格式如下:class 类名:接口名列表/类实体 说明:,当一个类实现一个接口时,这个类就必须实现整个接口,而不能选择实现接口的某一部分。一个接口可以由多个类来实现,而在一个类中也可以实现一个或多个接口。一个类可以继承一个基类,并同时实现一个或多个接口。,1. 隐式实现接口成员如果类实现了某个接口,它必然隐式地继承了该接

28、口成员,只不过增加了该接口成员的具体实现。若要隐式实现接口成员,类中的对应成员必须是公共的、非静态的,并且与接口成员具有相同的名称和签名。,【例7.6】 分析以下程序的运行结果 。,using System; namespace Proj7_6 interface Ia /声明接口Iafloat getarea(); /接口成员声明public class Rectangle : Ia /类A继承接口Ia float x,y;public Rectangle(float x1, float y1) /构造函数x = x1; y = y1;public float getarea() /隐式接口

29、成员实现,必须使用publicreturn x*y;,class Program static void Main(string args) Rectangle box1 = new Rectangle(2.5f, 3.0f); /定义一个类实例Console.WriteLine(“长方形面积: 0“, box1.getarea(); ,3 7,2. 显式实现接口成员当类实现接口时,如给出了接口成员的完整名称即带有接口名前缀,则称这样实现的成员为显式接口成员,其实现被称为显式接口实现。显式接口成员实现不能使用任何修饰符。,【例7.8】 分析以下程序的运行结果 。,using System; n

30、amespace Proj7_8 interface Ia /声明接口Iafloat getarea(); /接口成员声明public class Rectangle : Ia /类Rectangle继承接口Ia float x,y;public Rectangle(float x1, float y1) /构造函数x = x1; y = y1;float Ia.getarea() /显式接口成员实现,带有接口名前缀,不能使用publicreturn x*y;,class Program static void Main(string args) Rectangle box1 = new Re

31、ctangle(2.5f, 3.0f);/定义一个类实例Ia ia = (Ia)box1; /定义一个接口实例Console.WriteLine(“长方形面积: 0“, ia.getarea(); ,长方形面积:7.5,7.5 接口在集合排序中的应用,7.5.1 ArrayList类的排序方法ArrayList类对象不仅可以存放数值、字符串,还可以存放其他类的对象和结构变量。其提供的排序方法如下:,其中涉及到IComparable和IComparer两个系统接口。,ArrayList.Sort ():使用每个元素的IComparable接口实现对整个ArrayList中的元素进行排序。 Arr

32、ayList.Sort (IComparer):使用指定的比较器对整个ArrayList中的元素进行排序。 ArrayList.Sort (Int32, Int32, IComparer):使用指定的比较器对ArrayList中某个范围内的元素进行排序。,7.5.2 IComparable接口IComparable接口定义通用的比较方法,由值类型或类实现以创建类型特定的比较方法。其公共成员有CompareTo,它用于比较当前实例与同一类型的另一对象。其使用语法格式如下:int CompareTo(Object obj)其中,obj表示与此实例进行比较的对象。其返回值是一个32位有符号整数,指示

33、要比较的对象的相对顺序。返回值的含义如下:,小于零:此实例小于obj。 零:此实例等于obj。 大于零:此实例大于obj。,IComparable接口的CompareTo方法提供默认排序次序,如果需要改变其排序方式,可以在相关类中实现CompareTo方法,以订制其比较功能。,【例7.12】 分析以下程序的运行结果。,using System; using System.Collections; /新增 namespace Proj7_12 class Program class Stud : IComparable /从接口派生 int xh; /学号string xm; /姓名int fs

34、; /分数public int pxh /pxh属性get return xh; public string pxm /pxm属性get return xm; public int pfs /pfs属性get return fs; ,public Stud(int no, string name, int degree)xh = no; xm = name; fs = degree;public void disp() /输出学生信息Console.WriteLine(“t0t1t2“, xh, xm, fs);public int CompareTo(object obj) /实现接口方法

35、Stud s = (Stud)obj; /转换为Stud实例if (pfs s.pfs) return 1;else if (pfs = s.pfs) return 0;else return -1;static void disparr(ArrayList myarr, string str) /输出所有学生信息 Console.WriteLine(str);Console.WriteLine(“t学号t姓名t分数“);foreach (Stud s in myarr) s.disp(); ,static void Main(string args) int i, n = 4;ArrayLi

36、st myarr = new ArrayList();Stud st = new Stud4 new Stud(1, “Smith“, 82), new Stud(4, “John“, 88), new Stud(3, “Mary“, 95), new Stud(2, “Cherr“, 64) ;for (i = 0; i n; i+) /将对象添加到myarr集合中myarr.Add(sti);disparr(myarr, “排序前:“);myarr.Sort();disparr(myarr, “按分数降序排序后:“); ,7.5.3 IComparer接口,小于零:x小于y。零:x等于y。

37、大于零:x大于y。,通常声明一个类(从IComparer接口派生),其中实现Compare方法,以订制其比较功能,然后再调用排序方法以该类的对象作为参数,这样在排序时会自动使用该订制的Compare方法。,IComparer接口定义两个对象的通用比较方法。其公共成员有Compare。Compare方法比较两个对象并返回一个值,指示一个对象是小于、等于还是大于另一个对象。其使用语法格式如下:int Compare(Object x,Object y)其中,x表示要比较的第一个对象。y表示要比较的第二个对象。 其返回值是一个32位有符号整数,指示要比较的对象的相对顺序。返回值的含义如下:,例7.1

38、3】 分析以下程序的运行结果。,using System; using System.Collections; /新增 namespace Proj7_13 class Program class Stud int xh; /学号string xm; /姓名int fs; /分数public int pxh /pxh属性get return xh; public string pxm /pxm属性get return xm; public int pfs /pfs属性get return fs; ,public Stud(int no, string name, int degree)xh =

39、 no; xm = name; fs = degree;public void disp()Console.WriteLine(“t0t1t2“, xh, xm, fs);public class myCompareClassxh : IComparer int IComparer.Compare(object x, object y) Stud a = (Stud)x;Stud b = (Stud)y;if (a.pxh b.pxh) return 1;else if (a.pxh = b.pxh) return 0;else return -1;,public class myCompar

40、eClassxm : IComparer int IComparer.Compare(object x, object y) Stud a = (Stud)x;Stud b = (Stud)y;return String.Compare(a.pxm, b.pxm);public class myCompareClassfs : IComparer int IComparer.Compare(object x, object y) Stud a = (Stud)x;Stud b = (Stud)y;if (a.pfs b.pfs) return 1;else if (a.pfs = b.pfs)

41、 return 0;else return -1;,static void disparr(ArrayList myarr, string str) Console.WriteLine(str);Console.WriteLine(“t学号t姓名t分数“);foreach (Stud s in myarr)s.disp();,static void Main(string args) int i, n = 4;IComparer myComparerxh = new myCompareClassxh();IComparer myComparerxm = new myCompareClassxm

42、();IComparer myComparerfs = new myCompareClassfs();ArrayList myarr = new ArrayList();Stud st = new Stud4 new Stud(1, “Smith“, 82), new Stud(4, “John“, 88), new Stud(3, “Mary“, 95), new Stud(2, “Cherr“, 64) ;for (i = 0; i n; i+) myarr.Add(sti);disparr(myarr, “排序前:“);myarr.Sort(myComparerxh);disparr(m

43、yarr, “按学号升序排序后:“);myarr.Sort(myComparerxm);disparr(myarr, “按姓名词典次序排序后:“);myarr.Sort(myComparerfs);disparr(myarr, “按分数降序排序后:“); ,7.6 泛型编程,7.6.1 什么是泛型所谓泛型,是指通过参数化类型来实现在同一份代码上操作多种数据类型,泛型编程是一种编程范式,它利用“参数化类型”将类型抽象化,从而实现更为灵活的复用。C#泛型能力是由CLR在运行时支持,区别于C+的编译时模板机制和Java的编译时的“搽拭法”。这使得泛型能力可以在各个支持CLR的语言之间进行无缝的互操作

44、。,7.6.2 泛型的定义和使用通常先定义泛型,然后通过类型实例化来使用泛型。定义泛型的语法格式如下:访问修饰符返回类型 泛型名称其中,“泛型名称”要符合标识符的定义。尖括号表示类型参数列表,可以包含一个或多个类型参数,如。 C#中常用的泛型有泛型类和泛型方法,例如:class Stack /泛型类 T dataMaxSize;int top;void swap(ref T a,ref T b) /泛型方法 T tmp = a;a = b;b = tmp;,【例7.14】 分析以下程序的运行结果。,using System; using System.Collections.Generic;

45、using System.Text; namespace Proj7_14 class Stack T data;int top;public Stack() /构造函数 data = new T10; top=-1; public bool StackEmpty() return top=-1; public void Push(T e) top+; datatop=e; public void Pop(ref T e) e=datatop;top-;,class Program static void Main(string args) int e=0;Stack s=new Stack(

46、); /整数栈s.Push(1);s.Push(3);s.Push(2);Console.Write(“整数栈出栈次序“); while (!s.StackEmpty() s.Pop(ref e);Console.Write(“0 “,e);Console.WriteLine();,string e1=“;Stack s1 = new Stack(); /字符串栈s1.Push(“Mary“);s1.Push(“John“);s1.Push(“Simth“);Console.Write(“字符串栈出栈次序“);while (!s1.StackEmpty() s1.Pop(ref e1);Console.Write(“0 “, e1);Console.WriteLine(); ,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报