面向对象编程进阶.ppt_第1页
面向对象编程进阶.ppt_第2页
面向对象编程进阶.ppt_第3页
面向对象编程进阶.ppt_第4页
面向对象编程进阶.ppt_第5页
已阅读5页,还剩62页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第四章 面向对象编程进阶,本章学习目标,理解类的继承与多态的概念 熟悉类型转换的方法 掌握结构与接口的定义及用法 掌握异常处理的方法 掌握委托的定义及用法,第四章 面向对象编程进阶,4.1 类的继承与多态 4.3 类型转换 4.4 结构与接口 4.6 异常处理 4.7 委托,4.1 类的继承与多态,4.1.1 继承 4.1.2 多态,4.1.1 继承,类的继承性:C#允许基于某一个已经定义的类来创建一个新类。 基类:被继承的类,即父类。 派生类:继承的类,即子类。,4.1.1 继承,访问修饰符 class 类名 : 基类 类主体 访问修饰符: public:表示不限制对类的访问; internal: 可被同一个项目的程序访问; sealed: 表示一个密封类,不能被继承。 说明:如果对类不指定访问修饰符,则类的默认访问修饰符为internal,定义派生类,4.1.1 继承,class Person public string name; protect string sex; int age; class Student : Person string stuNo; string classNo; ,定义派生类,4.1.1 继承,派生类只能继承于一个基类; 派生类自然继承基类的成员,但不能继承基类的构造函数成员; 类的继承可以传递。如C类继承B类,B类继承A类,则C类即具有B类和A类的成员; 派生类是对基类的扩展,派生类定义中可以声明新的成员,但不能消除已继承的基类成员; 派生类定义中如果声明了与基类同名的成员,则基类的同名成员将被隐藏,从而使派生类不能直接访问同名的基类的成员; 基类可以定义虚方法成员等,这样派生类能够重载这些成员以表现类的多态性。,类的继承规则,4.1.1 继承,派生类构造函数,默认执行基类的无参构造函数,如果要执行基类有参构造函数,则必须在派生类构造函数的基表列表中指出; 如果基类具有带参数的构造函数,则派生类必需具有向基类传递参数的带参构造函数; 构造函数调用顺序:先基类后派生类。,派生类析构函数,析构函数调用顺序:先派生类后基类。,4.1.1 继承base,在派生类中调用基类方法 在构造函数中显式调用基类构造函数 public 派生类名(形参列表): base(基类构造函数实参列表) 在方法中调用基类方法 base.基类方法名(参数表),4.1.1 继承隐藏,隐藏 自动隐藏与基类同名的成员 声明成员时,显式使用new修饰符,隐藏实质上是使继承的成员在派生类成为不可见的。隐藏的成员并没有被删除,只是不能从派生类直接访问,通过基类能够直接访问它。,4.1.2 多态,编译时实现的多态: 如果一个类中有两个或两个以上的方法的名字相同,而它们的形参个数或形参类型有所不同,在程序编译时能够正确区别他们; 运行时实现的多态: 指在程序运行时,基类对象执行一个基类与派生类都具有的同名方法调用时,程序可以根据基类对象类型的不同(基类还是派生类)进行正确的调用。 实现方法:虚方法、抽象方法,4.1.2 多态虚方法,public virtual 返回类型 方法名(参数列表) 方法体 ,基类中定义虚方法,public override 返回类型 方法名(参数列表) 方法体 ,派生类中重写基类中定义虚方法,4.1.2 多态虚方法,几点说明: 基类与派生类中的方法名、参数列表、返回类型必须完全一致; 可被重写的基类方法是虚方法、抽象方法或重写方法(override修饰) virtual不能与static、abstract或override中任一个同时出现; override不能与new、static、virtual或abstract中任一个同时使用;,4.1.2 隐藏与多态实例,隐藏与多态,class A public void E() Console.WriteLine(“A.E”); public void F() Console.WriteLine(“A.F”); public virtual void G() Console.WriteLine(“A.G”); class B:A public void E() Console.WriteLine(“B.E”); public new void F() Console.WriteLine(“B.F”); public override void G() Console.WriteLine(“B.G”); class Test public static void Main() B b=new B(); A a=b; a.E(); b.E(); a.F(); b.F(); a.G(); b.G(); ,输出结果: A.E B.E A.F B.F B.G B.G,父类可以引用子类对象,父类引用只能调用子类继承自父类的方法,父类不能调用子类独有的方法。,4.1.2 隐藏与多态实例,隐藏与多态,class A public virtual void F() Console.WriteLine(“A.F”); class B:A public override void F() Console.WriteLine(“B.F”); class C :B new public virtual void F() Console.WriteLine(“C.F”); class D :C public override void F() Console.WriteLine(“D.F”); class Test public static void Main() D d=new D(); A a=d; B b=d; C c=d; a.F(); b.F(); c.F(); d.F(); ,输出结果: B.F B.F D.F D.F,4.1.2 多态抽象类与抽象方法,抽象类:是一种特殊的基类,该类并不与具体的事物发生联系;例如几何体,计算几何体体积的方法不可能有具体实现过程,只有具体某一种几何体才有求体积的方法; 抽象类是指在基类的定义中声明不包含任何实现代码的方法,实际上就是一个不具有任何具体功能的方法,即抽象方法。该方法的唯一作用就是让派生类来重写; 在基类定义中,只要类体中包含一个抽象方法,该类即为抽象类。,4.1.2 多态抽象类与抽象方法,public abstract class 类名 public abstract 返回类型 方法名称(参数列表); ,声明抽象类与抽象方法,不包含方法体, 也不能要,4.1.2 多态抽象类与抽象方法,抽象类几点说明 一个类中只要包含一个抽象方法,该类即为抽象类;反之,一个抽象类中必须包含抽象方法; 抽象类中可以包含非抽象方法; 抽象类不能实例化,不能用new生成实例; 抽象类不能被密封。 派生类说明 如果基类为抽象类,则要求派生类必须重载实现基类中所有抽象方法。 抽象方法说明 抽象方法没有方法体,只有一个方法头后跟一个分号; 抽象方法被隐含认为是一种虚方法,派生类中必须重写所有抽象方法,且重写的方法与抽象方法的参数及类型、方法名都应相同。,4.1.2 多态抽象类与抽象方法,public abstract class Shape protected double x; protected double y; protected double z; public Shape(double dx, double dy, double dz) x=dx; y=dy; z=dz; public abstract double Cubage(); ,定义抽象类及抽象方法,4.1.2 多态抽象类与抽象方法,public class Cuboid:Shape public Cuboid(double dx, double dy, double dz) :base(dx,dy,dz) public override double Cubage() return x * y * z; ,重载抽象方法,4.1.2 多态抽象类与抽象方法,虚方法与抽象方法区别 抽象方法必须在抽象类中定义,虚方法可以在抽象类或一般类中定义; 在基类中,虚方法用virtual关键字,抽象方法用abstract关键字; 在派生类中,虚方法不一定重写,抽象方法一定要重写;,修饰符小结,基类方法,abstract,virtual,override,无说明符,new (无说明符),override,派生类方法,4.1.2 多态密封类和密封方法,密封类:不允许被继承的类。,定义密封类,访问修饰符 sealed class 类名称 类体 ,public sealed class SealedClass public string method( ) return “我是密封类“; ,定义密封类,4.1.2 多态密封类和密封方法,基类中要密封的方法必须有virtual、abstract或override 派生类中的密封方法必须同时有sealed override。,定义密封方法,访问修饰符 sealed override 返回类型 方法名(参数列表) 方法体 ,4.1.2 多态密封类和密封方法,密封方法,class A public virtual void F() Console.WriteLine(“A.F”); class B:A public sealed override void F() Console.WriteLine(“B.F”); class C :B public override void F() Console.WriteLine(“C.F”); class Test public static void Main() C c=new C(); c.F(); ,sealed必须与override同时出现,不允许重写F方法 若无override则为隐藏,4.3 类型转换,4.3.1 隐式类型转换 4.3.2 显式类型转换 4.3.3 使用Convert转换,为什么需要类型转换,编译器要确切地知道数据的类型,int num = “123“ ;,整数,字符串,需要类型转换!,编译出错,4.3.1 隐式类型转换,隐式转换:自动类型转换,float,int,规则:对于数值类型,A的取值范围完全包含在B内,A,B,static void Main(string args) double score = 58.5; / 原始成绩 int bonus = 2; / 加分 int sum; / 总分 sum = score + bonus; / 计算总分 Console.WriteLine(sum); Console.ReadLine(); ,4.3.2 显式类型转换,static void Main(string args) double score = 58.5; int bonus = 2; int sum; sum = (int)score + bonus; Console.WriteLine(sum); Console.ReadLine(); ,明确告诉编译器转换类型 注意:double (58.5)-int (58),精度可能丢失!,显式转换:强制类型转换,使用 Parse() 进行转换,字符串和数值型的互相转换,int,float,double,string,int.Parse( ),float.Parse( ),double.Parse( ),ToString(),必须是数字的 有效表示形式!,4.3.3 使用 Convert 类进行转换,使用 Convert :Convert.ToXxx(object value),Convert.ToInt32(),Convert.ToSingle(),Convert.ToString(),double 85.63,string “85.63“,int 86,float 85.63,Parse 与 Convert,Xxx.Parse(string),目标类型的有效表示形式,Convert.ToXxx(object):,注:Xxx表示某种类型,字符串,其他类型,任意类型,其他类型,4.4 结构与接口,访问修饰符struct 结构名 结构主体 访问修饰符: public:表示不限制对结构的访问; internal: 可被同一个项目的程序访问(默认); 结构成员包括字段、属性、方法等; 结构可以定义构造函数,但不能定义析构函数; 定义构造函数时不能采用缺省方式(无参数)。,结构的声明,4.4 结构与接口,结构与类的区别,4.4 结构与接口,struct account public string name; public double balance; public account(string n,double b) name=n;balance=b; ,结构定义及使用(一),4.4 结构与接口,结构定义及使用(一)续,class Test public static void Main() account acc1=new account(“张三”,3000); /显式构造函数 account acc2=new account(); /缺省构造函数 account acc3; /没有构造函数 Console.WriteLine(+“has a balance of ”+acc1.balance); if(=null) Console.WriteLine(“ is null”); Console.WriteLine(“acc2.balance is”+acc2.balance); /使用acc3以前,必须初始化acc3 =“Mary”; acc3.balance=2000; Console.WriteLine(+“has a balance of ”+acc3.balance); ,4.4 结构与接口,struct MyStruct public int x; public int y; public MyStruct(int i, int j) x = i; y = j; public void Sum() int sum=x+y; Console.WriteLine(“The sum is 0”,sum); ,结构定义及使用(二),4.4 结构与接口,class Test static void Main() MyStruct s1 = new MyStruct(1,2); MyStruct s2 = s1; s1.x = 2; s1.Sum(); s2.Sum(); ,结构定义及使用(二)续,输出结果: The sum is 4 The sum is 3,值传递,4.4 结构与接口,接口声明定义了一个协定,使用接口的类或结构必须遵守其协定。接口可以从多个基接口继承,而类或结构可以实现多个接口; 接口成员只能是方法、属性、索引和事件,不能有字段。 接口本身不提供它所定义成员的实现代码,只指定实现该接口的类或结构必须提供的成员的调用形式。,4.4 结构与接口,访问修饰符 interface 接口名 :基接口1,基接口2 接口体 访问修饰符: public:表示不限制对类的访问; internal: 可被同一个项目的程序访问(默认); 接口成员包括属性、方法等; 接口不能包括字段,也不能定义构造函数和析构函数; 接口成员访问修饰符默认为public; 接口的命名通常是以I开头,如IPartA。,接口的声明,4.4 结构与接口,接口的实现 函数成员的实现:类、结构; 实现接口类型: public成员实现 显示接口成员实现 不能用new操作符创建接口的实例,4.4 结构与接口,public成员实现 实现接口成员时,声明成员为public,这样的实现声明称为public接口成员实现声明,简称public成员实现或public实现; public实现的成员具有双重访问性,因为它是接口成员的实现,所以可以通过接口实例来访问,又因为它是public成员,还可以通过类或结构的实例来访问。,4.4 结构与接口,interface IA void p(); class B:IA public void p() /代码实现 class Test public static void Main() B b=new B(); b.p(); IA a=b; a.p(); ,public成员实现(一),(正确),(正确),4.4 结构与接口,public成员实现(二),interface IPoint int Xget;set; int Yget;set; class MyPoint:IPoint private int myX,myY; public MyPoint(int x,int y) myX=x;myY=y; public int X /对属性X的public实现声明 getreturn myX; setmyX=value; public int Y /对属性Y的public实现声明 getreturn myY; setmyY=value; ,4.4 结构与接口,class MainClass /通过接口调用 public static void PrintPoint(IPoint p) Console.WriteLine(“x=0,y=1”,p.X,p.Y); public static void Main() MyPoint p=new MyPoint(2,3); Console.Write(“MyPoint:”); PrintPoint(p); ,public成员实现(二)续,输出结果: MyPoint:x=2,y=3,4.4 结构与接口,显式接口成员实现 用接口成员的完全限定名(接口名.成员名)来显式指定要实现的接口成员,这样的实现声明称为显式接口成员实现声明,简称显式实现声明; 注意:显式实现声明中不能用public修饰符。,4.4 结构与接口,interface IA void p(); class B:IA void IA.p() /代码实现 class Test public static void Main() B b=new B(); b.p(); IA a=b; a.p(); ,显式成员实现(一),(错误),(正确),4.4 结构与接口,interface IA void p(); interface IB void p(); class C:IA,IB void IA.p()Console.WriteLine(“A.p”); void IB.p()Console.WriteLine(“B.p”); public void p() Console.WriteLine(“C.p”); class Test public static void Main() C c=new C(); c.p(); (IA)c).p(); (IB)c).p(); ,显式成员实现(二),输出结果: C.p A.p B.p,4.4 结构与接口,interface IA void p(); class B:IA void IA.p()Console.WriteLine(“A.p”); public void p() Console.WriteLine(“B.p”); class C:B,IA public static void Main() B b=new B(); IA a=b; a.p(); /显式接口成员实现优先 C c=new C(); a=c; c.p(); a.p(); ,显式成员实现(三),输出结果: A.p B.p A.p,类可以同时有一个基类和零个以上的接口,并将基类写在前面,4.6 异常处理,异常 指由于程序运行时发生的错误,从而导致程序错误结束。 异常处理 当程序运行过程中发生了某个异常现象,系统将产生一个相应的异常类对象,并把它交给系统处理,系统负责找到处理错误的代码并执行, 如除数为0。,4.6 异常处理,使用语句或表达式在执行过程中自动引发了某个异常的条件,使得操作无法正常结束,从而引发异常; 使用显式 throw 语句来引发异常。在此情况下,控制权将无条件转到处理异常的部分代码。,引发异常两种方式,C#中异常处理语句,trycatch trycatchfinally tryfinally throw,4.6 异常处理,try 被监控的可能发生异常的程序代码 catch(异常类名 异常变量名) 异常处理 ,格式1,try 被监控的可能发生异常的程序代码 finally 最终要执行的代码 ,格式2,try 被监控的可能发生异常的程序代码 catch(异常类名 异常变量名) 异常处理 finally 最终要执行的代码 ,格式3,4.6 异常处理,try子句包含可能引起异常的代码; 只有发生异常时才执行catch子句,若没有异常,try子句正常结束,catch子句被忽略,程序转到catch后的第一条语句开始执行; 可以包含多个catch语句; catch子句可以不包括参数,它将捕获所有类型的异常; 异常类名必须为System.Exception或从System.Exception派生的类型; finally子句不管有没有异常都执行。,4.6 异常处理,4.6 异常处理,int num1, num2,result; try num1 = int.Parse(Console.ReadLine(); num2 = int.Parse(Console.ReadLine(); result = num1 / num2; Console.WriteLine(“商是”+result); catch(DivideByZeroException error) Console.WriteLine(“除数不能为零!“); catch (FormatException error) Console.WriteLine(“输入格式错误!“); catch(Exception ex) /如果写,写在catch的最后 Console.WriteLine(“输入错误”); finally Console.WriteLine(“谢谢使用!“);,异常处理,4.6 异常处理,throw异常处理,static int Divide(int x,int y) try int z=x/y; return z; catch(DivideByZeroException error) throw new DivideByZeroException(“除数不能为0”); ,static void Main() int num1, num2,result; try num1 = int.Parse(Console.ReadLine(); num2 = int.Parse(Console.ReadLine(); result = Divide(num1,num2); Console.WriteLine(“商是”+result); catch(DivideByZeroException error) Console.WriteLine(error.Message); catch (FormatException error) Console.WriteLine(“输入格式错误!“); catch(Exception ex) Console.WriteLine(“输入错误”); finally Console.WriteLine(“谢谢使用!“); ,4.7 委托,委托也叫代理,就是把事情交给别人去办,如委托律师代理打官司,委托同学代买火车票; C#中如果将一个方法委托给一个代理对象,那么这个对象就可以全权代理这个方法的执行; 使用委托首先要定义委托,声明委托能代理什么类型的方法,就像房产中介能代理抵押贷款业务,而不能代理打官司; 委托是一种类型,即它与class , interface , struct ,enum处于同一级别,而且它是引用类型; 任何委托类型都是system.delegate类的派生类。,4.7 委托,何时使用委托? (1)回调函数; (2)多线程编程中使用委托来指定启动一个线程时调用的方法; (3)C#中的事件模型。用它们指明处理给定事件的方法。,4.7 委托,委托用法步骤: (1)定义委托 访问修饰符 delegate 代理方法的返回值类型 委托类型名(代理方法参数列表) (2)声明委托变量 委托类型名 委托对象; (3)实例化委托变量 委托对象=new 委托类型(对象名.方法名)/调用某类的实例方法 委托对象=new 委托类型(类名.方法名)/调用某类的静态方法 (4)调用委托,实现方法 委托对象(实参),实例化时必须指定方法名,4.7 委托,Void Multiply(int,int) . Void Divide(int,int) . ,可以引用任何方法,将在运行时决定,委托和方法必须具有相同的签名,- public delegate void Call(int num1, int num2); -,4.7 委托,定义委托,namespace Delegates public delegate int Call(int num1, int num2); class Math public int Multiply(int num1, int num2) return num1*num2; public int Divide(int num1, int num2) return num1/num2; class TestDelegates public static void Main() Call objCall; Math math = new Math(); objCall = new Call(math.Multiply); Console.WriteLine(“乘积是:”+objCall(1,2); ,将方法与委托关联起来,4.7 委托,回调函数,namespace Delegates public delegate int Call(int num

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论