C#的面向对象程序设计.ppt

上传人:桔**** 文档编号:568513044 上传时间:2024-07-25 格式:PPT 页数:77 大小:372KB
返回 下载 相关 举报
C#的面向对象程序设计.ppt_第1页
第1页 / 共77页
C#的面向对象程序设计.ppt_第2页
第2页 / 共77页
C#的面向对象程序设计.ppt_第3页
第3页 / 共77页
C#的面向对象程序设计.ppt_第4页
第4页 / 共77页
C#的面向对象程序设计.ppt_第5页
第5页 / 共77页
点击查看更多>>
资源描述

《C#的面向对象程序设计.ppt》由会员分享,可在线阅读,更多相关《C#的面向对象程序设计.ppt(77页珍藏版)》请在金锄头文库上搜索。

1、第第6章章 C#的面向对象程序设计的面向对象程序设计内容提要:内容提要: 类、对象的概念及使用类、对象的概念及使用 方法、属性、索引的概念、声明及调用方法、属性、索引的概念、声明及调用 构造函数和析构函数的定义构造函数和析构函数的定义 继承和接口的用法继承和接口的用法 委托和事件的声明及调用委托和事件的声明及调用目的要求:目的要求: 理解类、对象、构造函数和析构函数的意义理解类、对象、构造函数和析构函数的意义 掌握方法、属性、索引的用法掌握方法、属性、索引的用法 掌握继承和接口、委托和事件的声明及调用掌握继承和接口、委托和事件的声明及调用重点难点:重点难点: 类、对象、方法、属性、继承、接口、

2、委托和事件类、对象、方法、属性、继承、接口、委托和事件 面向对象的程序设计面向对象的程序设计( OOP )的主要思想是将数据及处的主要思想是将数据及处 理这些数据的操作都封装到一个称为类(理这些数据的操作都封装到一个称为类(Class)的数据结的数据结 构中。使用这个类时,只需要定义一个类的变量即可,这构中。使用这个类时,只需要定义一个类的变量即可,这 个变量叫做对象(个变量叫做对象(Object)。)。通过调用对象的数据成员完通过调用对象的数据成员完 成对类的使用。成对类的使用。 1. 类类 在面向对象理论中,类(在面向对象理论中,类(class)就是对具有相同特征就是对具有相同特征的一类事

3、物所做的抽象(或者说,归纳)。的一类事物所做的抽象(或者说,归纳)。 6.1 面向对象程序设计的基本概念面向对象程序设计的基本概念 2. 对象对象 类是一种抽象,而对象类是一种抽象,而对象(object)则是实例则是实例(instance), 是具体的。是具体的。 如果使用如下格式来代表一个类生成一个对象:如果使用如下格式来代表一个类生成一个对象: 类名类名 对象名;对象名; 则:则: 电子计算机电子计算机 ComputerA; 电子计算机电子计算机 ComputerB; 就代表就代表ComputerA和和ComputerB是是“电子计算机电子计算机”类类的的 两个不同对象。两个不同对象。 3

4、. 类的属性类的属性 属性说明了这个类的特点。属性说明了这个类的特点。 例如例如“PC计算机计算机”类则可能具备如下属性:类则可能具备如下属性: 计算机的名称计算机的名称 CPU类型类型 内存容量内存容量 硬盘容量硬盘容量 主板型号主板型号 显示适配器型号显示适配器型号 声卡型号声卡型号 操作系统类型操作系统类型 通过这些属性,就可以将不同的通过这些属性,就可以将不同的PC计算机区分开。计算机区分开。 4. 类的方法类的方法 类的方法(类的方法(method)代表了一类事物所具备的动作,代表了一类事物所具备的动作, 是对属性的操作。是对属性的操作。 比如:比如:“石英钟石英钟”类的方法有:秒针

5、前进一格、分秒类的方法有:秒针前进一格、分秒针针 前进一格、时针前进一格等,而前进一格、时针前进一格等,而“录像机录像机”类所具备的方类所具备的方法法 可以有:播放、定格、录像、倒带、快进等。可以有:播放、定格、录像、倒带、快进等。 5. 派生和继承派生和继承 在类的继承中,被继承的类称为基类(又称为父类),在类的继承中,被继承的类称为基类(又称为父类), 由基类继承的类称为派生类(又称为子类)。派生类自动获由基类继承的类称为派生类(又称为子类)。派生类自动获 得基类的所有属性和方法,而且可以在派生类中添加新的属得基类的所有属性和方法,而且可以在派生类中添加新的属 性和方法。性和方法。 6.

6、多态性多态性 多态性是指在一般类中定义的属性或行为,被特殊多态性是指在一般类中定义的属性或行为,被特殊 类继承之后,可以具有不同数据类型或表现出不同的行类继承之后,可以具有不同数据类型或表现出不同的行 为。就是程序在运行时,会自动判断对象的派生类型,为。就是程序在运行时,会自动判断对象的派生类型, 并调用相应的方法。并调用相应的方法。 7. 封装封装 封装就是把对象的属性和服务结合成一个独立的系封装就是把对象的属性和服务结合成一个独立的系 统单位,并尽可能隐蔽对象的内部细节统单位,并尽可能隐蔽对象的内部细节。 6.2 类和对象类和对象 6.2.1 类的声明类的声明 类是类是C#的一种自定义数据

7、类型,其声明格式为:的一种自定义数据类型,其声明格式为: 类修饰符类修饰符 class 类名类名:基类类名:基类类名 类的成员;类的成员; ; 说明:说明:C#支持的类修饰符有:支持的类修饰符有:new、public、protected、 internal、private、abstract、sealed。 例:定义一个车辆类(有三个变量)例:定义一个车辆类(有三个变量) class Vehicle public int passengers; /乘客数乘客数 public int fuelcap; /所耗所耗燃料燃料 public int mpg; /每每公里耗油量公里耗油量 6.2.2 类的

8、成员类的成员 类的成员可以分为两大类:类本身所声明的,以及类的成员可以分为两大类:类本身所声明的,以及从基类其分为两种:从基类其分为两种: 一种不以函数形式体现,称为成员变量;一种不以函数形式体现,称为成员变量; 另一种是以函数形式体现,称为成员函数。另一种是以函数形式体现,称为成员函数。 1. 类成员的访问修饰符类成员的访问修饰符 (1)public: 允许类的内部或外界直接访问;允许类的内部或外界直接访问; (2)private: 不允许外界访问,也不允许派生不允许外界访问,也不允许派生类类 访问,即只能在类的内部访问。如访问,即只能在类的内部访问。如 果没有设定访问修饰符,默认为果没有设

9、定访问修饰符,默认为 private; (3)protected: 不允许外界访问,但允许派生类不允许外界访问,但允许派生类 访问;访问; (4)internal: 只有本类的成员才能访问。只有本类的成员才能访问。 (5)readonly:该成员的值只能读,不能写。也就:该成员的值只能读,不能写。也就 是说,除了赋予初始值外,在程序是说,除了赋予初始值外,在程序 的任何一个部分将无法更改这个成的任何一个部分将无法更改这个成 员的值。员的值。 class ClassA public int a; private int b; protected int c; public void SetA(

10、) a=1; /正确,允许访问类自身公有成员正确,允许访问类自身公有成员 b=2; /正确,允许访问类自身私有成员正确,允许访问类自身私有成员 c=3; /正确,允许访问类自身保护成员正确,允许访问类自身保护成员 class ClassB:ClassA public void SetB( ) ClassA BaseA=new ClassA( ); BaseA.a=5; /正确,允许访问基类公有成员正确,允许访问基类公有成员 BaseA.b=23; /错误,不允许访问基类私有成员错误,不允许访问基类私有成员 BaseA.c=68; /正确,允许访问基类保护成员正确,允许访问基类保护成员 clas

11、s ClassC public void SetB( ) ClassA BaseA=new ClassA( ); BaseA.a=5; /正确,允许访问类的其他公有成员正确,允许访问类的其他公有成员 BaseA.b=23; /错误,不允许访问类的其他私有成员错误,不允许访问类的其他私有成员 BaseA.c=68; /错误,不允许访问类的其他保护成员错误,不允许访问类的其他保护成员 2. 静态成员与非静态成员静态成员与非静态成员 静态成员是在声明成员时在前面加上静态成员是在声明成员时在前面加上static保留字;保留字; 非静态成员是在声明成员时前面没有非静态成员是在声明成员时前面没有stati

12、c保留字;保留字; 静态成员属于类所有,非静态成员属于类的对象所有。静态成员属于类所有,非静态成员属于类的对象所有。 静态成员的访问格式:静态成员的访问格式: 类名类名.静态成员名静态成员名 若将类中的某个成员声明为若将类中的某个成员声明为static,则该成员称为则该成员称为静态静态 成员成员。类中的成员要么是静态的,要么是非静态的。类中的成员要么是静态的,要么是非静态的。 类的类的非静态非静态成员属于类的实例所有,每创建一个类的成员属于类的实例所有,每创建一个类的 实例都在内存中为非静态成员开辟了一块区域。而类的静实例都在内存中为非静态成员开辟了一块区域。而类的静 态成员属于类所有,为这个

13、类的所有实例所共享。无论这态成员属于类所有,为这个类的所有实例所共享。无论这 个创建了多少个对象(实例),一个静态成员在内存中只个创建了多少个对象(实例),一个静态成员在内存中只 占有一块区域。占有一块区域。例:静态成员的访问例:静态成员的访问using System;class Myclass public int nIndex=10; static public double fphi=45.6; class classTest static void Main( ) int a=Myclass.nIndex; /错误,因为错误,因为nIndex是非是非静态成员静态成员 double b=

14、 Myclass.fphi; /正确,因为正确,因为fphi是静态是静态成员成员 Console.Write(b); 6.2.3 对象的声明对象的声明 创建类的对象。分两步:创建类的对象。分两步: (1)先声明对象名)先声明对象名 格式:格式: 类名类名 对象名;对象名; 例:例:Vehicle minivan; /定义类定义类Vehicle的的一个对象一个对象 (2)创建类的实例。)创建类的实例。 格式:对象名格式:对象名=new 类名类名( ); 例:例:minivan=new Vehicle( ); /创建一个实例创建一个实例 以上两步也可以合并成一步。以上两步也可以合并成一步。 格式:

15、格式: 类名类名 对象名对象名=new 类名类名( ) ; 例:例: Vehicle minivan =new Vehicle( );6.3 构造函数和析构函数构造函数和析构函数 C#C#中有两个特殊的函数:构造函数和析构函数。中有两个特殊的函数:构造函数和析构函数。 构造函数构造函数:当类实例化时首先执行的函数;:当类实例化时首先执行的函数; 析构函数析构函数:当实例(即对象)从内存中销毁前最后执行:当实例(即对象)从内存中销毁前最后执行 的函数。的函数。 6.3.1 构造函数构造函数 在在C#中,当创建一个对象时,系统首先为这个对中,当创建一个对象时,系统首先为这个对象赋予一个标识符,然后

16、给对象分配合适的内存空间,象赋予一个标识符,然后给对象分配合适的内存空间,随后系统就自动调用对象的构造函数。随后系统就自动调用对象的构造函数。 构造函数的类型修饰符总是构造函数的类型修饰符总是public,因为构造函数,因为构造函数主要是在类外创建对象时自动调用。主要是在类外创建对象时自动调用。格式:格式: class 类名类名 public 类名类名( ) /构造函数体构造函数体 例:例:using System; class MyClass public int x; public Myclass() /类类MyClass的构造函数的构造函数 x=10; class ConsDemo pu

17、blic static void Main() MyClass t1=new MyClass(); MyClass t2=new MyClass(); Console.WriteLine(“0t1”,t1.x, t2.x); 运行结果如下:运行结果如下: 构造函数也可以带参数。构造函数也可以带参数。 例:例:using System; class Fruit public string color; public string shape; public Fruit(string c,string s) /类类Fruit的构造函数的构造函数 color=c; shape=s; class Te

18、st public static void Main() Fruit Orange=new Fruit(“orange”,”round”);/创建创建Orange实例实例 Console.WriteLine(“0,1”,Orange.color, Orange.shape); 运行结果如下:运行结果如下: 构造函数也可以重载。构造函数也可以重载。例:例:using System; class A public int count;public A() count=-1; public A(int n) count=n; class Test static void Main() A a=new

19、 A(); Console.WriteLine(count=0,a.count); A b=new A(5);Console.WriteLine(count=0,b.count); 运行结果如下:运行结果如下:使用使用 this关键字关键字 C#中的中的this关键字是用来代表对象自身。关键字是用来代表对象自身。this一般用在构造函数中,一般用在构造函数中, 以便区别同名的构造函数参数和类成员变量。以便区别同名的构造函数参数和类成员变量。例:例: using System; class Point int x,y; public Point(int x,int y) this.x=x; th

20、is.y=y; 运行结果如下:运行结果如下: class Test static void Main() Point p=new Point(5,6); Console.WriteLine(x=0,p.x); Console.WriteLine(y=0,p.y); 6.3.2 析构函数析构函数 析构函数也是类的特殊的成员函数,它主要用析构函数也是类的特殊的成员函数,它主要用于释放类实例。于释放类实例。 析构函数的特殊性表现在以下几个方面:析构函数的特殊性表现在以下几个方面: (1)析构函数的名字与类名相同,但它前面需)析构函数的名字与类名相同,但它前面需要要 加一个加一个“”符号;符号; (2

21、)析构函数不能带参数,也没有返回值;)析构函数不能带参数,也没有返回值; (3)当撤消对象时,自动调用析构函数;)当撤消对象时,自动调用析构函数; (4)析构函数不能被继承,也不能被重载。)析构函数不能被继承,也不能被重载。格式:格式: class 类名类名 类名类名( ) /析构函数体析构函数体 析构函数以与构造函数相反的顺序被调用。析构函数以与构造函数相反的顺序被调用。例:例:using System; class Decon1 public Decon1( ) Console.WriteLine(“调用构造函数调用构造函数Decon1”); Decon1( ) Console.Write

22、Line(“调用析构函数调用析构函数Decon1”); class Decon2 public Decon2( ) Console.WriteLine(“调用构造函数调用构造函数Decon2”); Decon2( ) Console.WriteLine(“调用析构函数调用析构函数Decon2”); class Test public static void Main() Decon1 dec1=new Decon1( ); Decon2 dec2=new Decon2( ); 运行结果如下:运行结果如下: 可以按照程序代码执行的功能或其他依据把相关的可以按照程序代码执行的功能或其他依据把相关的

23、语句组织在一起,并给它们注明相应的名称,利用这种语句组织在一起,并给它们注明相应的名称,利用这种方式把程序分块,就形成了类的方法。方式把程序分块,就形成了类的方法。 方法的功能是通过方法调用实现的。方法调用指定方法的功能是通过方法调用实现的。方法调用指定了被调用方法的名字和调用方法所需的信息(参数),了被调用方法的名字和调用方法所需的信息(参数),调用方法要求被调用方法按照方法参数完成某个任务,调用方法要求被调用方法按照方法参数完成某个任务,并在完成这项任务后由方法返回。如果调用过程出错,并在完成这项任务后由方法返回。如果调用过程出错,则无法完成正常的任务。则无法完成正常的任务。6.4 方法方

24、法6.4.1 方法的定义及调用方法的定义及调用 方法是类中用于计算或进行其他操作的成员。类的方方法是类中用于计算或进行其他操作的成员。类的方法主要用来操作类的数据,提供一种访问数据的途径。法主要用来操作类的数据,提供一种访问数据的途径。 1. 方法的定义方法的定义 格式:格式: 修饰符修饰符 返回值类型返回值类型 方法名(形式参数列表)方法名(形式参数列表) 方法体各语句;方法体各语句; 说明:说明:(1)如果如果省略省略“方法修饰符方法修饰符”,该方法为类的该方法为类的私私 有成员。有成员。 (2)“返回类型返回类型”指定该方法返回数据的类型,指定该方法返回数据的类型, 它可以是任何有效的类

25、型。如果方法不需它可以是任何有效的类型。如果方法不需 要返回一个值,其返回类型必须是要返回一个值,其返回类型必须是void。 (3) “方法参数列表方法参数列表”是用逗号分隔的类型、是用逗号分隔的类型、标标 识符对。这里的参数是形式参数,本质上识符对。这里的参数是形式参数,本质上 是一个变量,它用来在调用方法时接收传是一个变量,它用来在调用方法时接收传 给方法的实际参数值,如果方法没有参给方法的实际参数值,如果方法没有参 数,那么参数列表为空。数,那么参数列表为空。2. 从方法返回从方法返回 一般来说有两种情况将导致方法返回。一般来说有两种情况将导致方法返回。 第一种情况:当碰到方法的结束花括

26、号。第一种情况:当碰到方法的结束花括号。 第二种情况:执行到第二种情况:执行到return语句。语句。 有两种形式的有两种形式的 return:一种用在一种用在void方法中(就是那方法中(就是那些没有返回值的方法),另一种用在有返回值的方法中。些没有返回值的方法),另一种用在有返回值的方法中。 例:通过方法的结束花括号返回。例:通过方法的结束花括号返回。 using System; class Test public void myMeth( ) int j; for(j=0;j=5) j=j*2; Console.WriteLine(j ); return; else j=j*3; Con

27、sole.WriteLine(j ); return; static void Main( ) Test lei=new Test( ); lei.myMeth( ); 运行结果如下:运行结果如下: 注意:一个注意:一个void方法在下述情况之一下将返回方法在下述情况之一下将返回程序执行时碰到方法的结束花括号;或者程序执行程序执行时碰到方法的结束花括号;或者程序执行到一条到一条return语句时。语句时。 使用下述形式的使用下述形式的return语句来从方法返回一个值语句来从方法返回一个值给调用者。给调用者。 格式:格式: return value; 说明:这里说明:这里value是要从方法中

28、返回的值。是要从方法中返回的值。 例:例:用用return语句返回值。语句返回值。 public int myMeth( ) int j= 8; if(j=5) return j*2; else return j*3; 6.4.2 方法的参数类型方法的参数类型 调用方法时,可以给方法传递一个或多个值。调用方法时,可以给方法传递一个或多个值。传给方法的值叫做实参(传给方法的值叫做实参(argument),在方法内部,在方法内部,接收实参值的变量叫做形参(接收实参值的变量叫做形参(parameter),形参在紧形参在紧跟着方法名的括号中声明。形参的声明语法与变量跟着方法名的括号中声明。形参的声明语

29、法与变量的声明语法一样。形参只在方法内部有效,除了将的声明语法一样。形参只在方法内部有效,除了将接收实参的值外,它与一般的变量没什么区别。接收实参的值外,它与一般的变量没什么区别。 C#方法的参数类型主要有:值参数、引用参数方法的参数类型主要有:值参数、引用参数和输出参数。和输出参数。 1值参数值参数 未用任何修饰符声明的参数为值参数。值参数在调用该参数所属的函数成员时创建,并用调用中给定的实参值初始化。当从该函数返回时值参数被销毁。对值参数的修改不会影响到原自变量。值参数通过复制原自变量的值来初始化。例:使用值参数。例:使用值参数。using System;class Test public

30、 void Swap(int x,int y) int k; k=x; x=y; y=x; static void Main() int a=8, b=68; Console.WriteLine(a=0, y=1, a, b); Test sw=new Test(); sw.Swap(a, b); Console.WriteLine(a=0, y=1, a, b);程序的运行结果为:程序的运行结果为: a=8, b=68 a=8, b=68 2. 引用型参数引用型参数 用用ref修饰符声明的参数为引用参数。引用参数本修饰符声明的参数为引用参数。引用参数本身并不创建新的存储空间,而是将实参的存储

31、地址传身并不创建新的存储空间,而是将实参的存储地址传递给形参。可以认为引用参数中就是调用方法时给出递给形参。可以认为引用参数中就是调用方法时给出的变量,而不是一个新变量。在函数调用中,引用参的变量,而不是一个新变量。在函数调用中,引用参数必须被赋初值。在调用时,传送给数必须被赋初值。在调用时,传送给ref参数的必须是参数的必须是变量,类型必须相同,并且必须使用变量,类型必须相同,并且必须使用ref修饰。修饰。 格式:格式: 方法修饰符方法修饰符 返回类型返回类型 方法名(方法名(,ref参数参数1, ref 参数参数 2,) 方法实现部分;方法实现部分; 调用方法时,实参前面也必须要加上调用方

32、法时,实参前面也必须要加上ref。例:使用引用参数。例:使用引用参数。using System;using System;class Testclass Test public void public void Swap(refSwap(ref intint x,refx,ref intint y) y) intint k; k; k=x; k=x; x=y; x=y; y=x; y=x; static void Main()static void Main() intint a=8, b=68; a=8, b=68; Console.WriteLine(aConsole.WriteLine(

33、a=0, y=1, a, b);=0, y=1, a, b); Test Test swsw=new Test();=new Test(); sw.Swap(refsw.Swap(ref a, ref b); a, ref b); Console.WriteLine(aConsole.WriteLine(a=0, y=1, a, b);=0, y=1, a, b); 程序的运行结果为:程序的运行结果为: a=8, b=68 a=68, b=8 3. 输出参数输出参数 用用out修饰符定义的参数称为输出参数。如果希望方法返回修饰符定义的参数称为输出参数。如果希望方法返回 多个值,可使用输出参数。

34、多个值,可使用输出参数。 格式:格式: 方法修饰符方法修饰符 返回类型返回类型 方法名(方法名(,out 参数参数1, out 参数参数 2,) 方法实现部分;方法实现部分; 调用方法时,实参前面也要加上调用方法时,实参前面也要加上out。例:使用输出参数例:使用输出参数using System;class MyClass public string TestOut(out string i) i=使用使用out关键字关键字; return out参数参数; class test static void Main() string x; MyClass app=new MyClass(); C

35、onsole.WriteLine(app.TestOut(out x); Console.WriteLine(x); 运行结果如下:运行结果如下:例:例:using System;class TestOut /b就是利用就是利用out这个输出参数而返回的值这个输出参数而返回的值 static int OutValue(int a,out char b) b=(char)a;return 9;static void Main()int t=65,r;char m;r=OutValue(t,out m);Console.WriteLine(r=0,m=1,r,m); 运行结果如下:运行结果如下:

36、注意:注意: 在把引用型实参的值传递给形参之前,必须先在把引用型实参的值传递给形参之前,必须先对其赋值。这一点是引用参数与输出参数的不同之对其赋值。这一点是引用参数与输出参数的不同之处。处。 在带有引用参数的方法中,有可能导致多个变在带有引用参数的方法中,有可能导致多个变量名指向同一内存地址,从而导致出错。量名指向同一内存地址,从而导致出错。6.4.2 方法的重载方法的重载 类中两个以上的方法类中两个以上的方法(包括隐藏的继承而来的方包括隐藏的继承而来的方法法)取的名字相同,只要使用的参数类型或参数个数取的名字相同,只要使用的参数类型或参数个数不同,编译器便知道在何种情况下应该调用哪个方不同,

37、编译器便知道在何种情况下应该调用哪个方法,这就叫做方法的重载。法,这就叫做方法的重载。 方法重载必须遵守一个重要的约束:每一个被方法重载必须遵守一个重要的约束:每一个被重载方法的参数类型或个数必须不同。当调用重载重载方法的参数类型或个数必须不同。当调用重载方法时,将执行形参与实参相匹配的那个方法。方法时,将执行形参与实参相匹配的那个方法。 例:方法重载。例:方法重载。 using System;using System; class class TestoverLoadTestoverLoad public void public void print(intprint(int i) i) C

38、onsole.WriteLineConsole.WriteLine(输出的整数输出的整数=0=0,i);i); public void public void print(stringprint(string s) s) Console.WriteLineConsole.WriteLine(输出的字符串输出的字符串=0, s);=0, s); public void public void print(doubleprint(double d) d) Console.WriteLineConsole.WriteLine(输出的双精度数输出的双精度数=0=0,d);d); class test

39、class test public static void Main( ) public static void Main( ) TestoverLoadTestoverLoad app=new app=new TestoverLoadTestoverLoad( );( ); app.print(6); app.print(6); app.printapp.print(理解方法重载了吗?理解方法重载了吗? );); app.print(3.14);app.print(3.14); 运行结果为:运行结果为: 输出的整数输出的整数=6 输出的字符串输出的字符串=理解方法重载了吗?理解方法重载了吗?

40、 输出的双精度数输出的双精度数=3.14 6.4.4 静态方法与非静态方法静态方法与非静态方法 类的成员类型有静态和非静态两种,因此方法也有静态类的成员类型有静态和非静态两种,因此方法也有静态方法和非静态方法两种。使用方法和非静态方法两种。使用static 修饰符的方法称为静态方修饰符的方法称为静态方法,没有使用法,没有使用static 修饰符的方法称为非静态方法。修饰符的方法称为非静态方法。 静态方法和非静态方法的区别是:静态方法属于类所有,静态方法和非静态方法的区别是:静态方法属于类所有,非静态方法属于用该类定义的对象所有。非静态方法属于用该类定义的对象所有。 例:使用静态方法和非静态方法

41、。例:使用静态方法和非静态方法。 using System;class TestMethod public int a; static public int b; void Fun1( ) /定义一个非静态方法定义一个非静态方法 a = 10; /正确,直接访问非静态成员正确,直接访问非静态成员 b = 20; /正确,直接访问静态成员正确,直接访问静态成员 static void Fun2( ) /定义一个静态成员方法定义一个静态成员方法 a = 10; /错误,不能访问非静态成员错误,不能访问非静态成员 b = 20; /正确,可以访问静态成员,相当于正确,可以访问静态成员,相当于myCl

42、ass.b = 20 class Teststatic void Main( ) myClass A = new myClass( ); A.a = 10; /正确,访问类正确,访问类myClass的非静态公有成员变量的非静态公有成员变量 A.b = 10; /错误,不能直接访问类中静态公有成员错误,不能直接访问类中静态公有成员 MyClass.a = 20; /错误,不能通过类访问类中非静态公有成员错误,不能通过类访问类中非静态公有成员 MyClass.b = 20; /正确,可以通过类访问类正确,可以通过类访问类myClass中的中的 /静态公有成员静态公有成员 6.4.5 运算符的重载运

43、算符的重载为类定义自己的运算符的操作,就称为运算符重载。为类定义自己的运算符的操作,就称为运算符重载。1运算符重载的声明运算符重载的声明 C# 中运算符重载总是在类进行声明。实际上中运算符重载总是在类进行声明。实际上一个运算符重载不过是一个方法罢了,比较特别的是它一个运算符重载不过是一个方法罢了,比较特别的是它的名称需要遵守一个特殊的格式来定义。所有的重载运的名称需要遵守一个特殊的格式来定义。所有的重载运算符的名称都是以算符的名称都是以operator开始,加上欲重载的运算符,开始,加上欲重载的运算符,而且重载运算符的方法一定是而且重载运算符的方法一定是public且为且为static的。的。

44、 声明重载运算符的一般格式如下:声明重载运算符的一般格式如下: public static 返回类型返回类型 operator 运算符运算符(参数列表参数列表) /可执行语句可执行语句 C#中下列运算符都是可以重载的:中下列运算符都是可以重载的: 一元运算符:一元运算符:+ - ! + - true false 二元运算符:二元运算符:+ - * / % & | = != = 和和,以及,以及=同样如此。同样如此。同样,同样,true与与false也必须成对出现。也必须成对出现。C#中还有一些运算符是允许重载的中还有一些运算符是允许重载的,如下所示:,如下所示: = & ?: new type

45、of sizeof is2一元运算符重载一元运算符重载 一元运算符重载必须使用类一元运算符重载必须使用类T的单个参数,的单个参数,其中其中+、-、!可以返回任何类型;、!可以返回任何类型;+或或-的的返返回类型必须是类回类型必须是类T,而且重载之后的,而且重载之后的+或或 -无无法区分前缀与后缀;法区分前缀与后缀;true和和false要求返回类型要求返回类型是是布尔类型。布尔类型。3二元运算符重载二元运算符重载 二元运算符重载必须有两个参数,而且其二元运算符重载必须有两个参数,而且其中至少一个必须是声明运算符的类类型。一个中至少一个必须是声明运算符的类类型。一个二元运算符可以返回任何类型。二

46、元运算符可以返回任何类型。6.4.6 递归递归 类方法成员间允许相互调用,也可以自己调用自己。类方法成员间允许相互调用,也可以自己调用自己。类的方法如果在方法体内直接或间接地类的方法如果在方法体内直接或间接地自己调用自己自己调用自己就称就称为为递归方法递归方法。 递归是常用的程序设计技术,其基本思想就是递归是常用的程序设计技术,其基本思想就是“自己自己调用自己调用自己”。 递归方法实际上体现了递归方法实际上体现了“依此类推依此类推”、“用同样的步骤重复用同样的步骤重复”这样的思想,它可以用简单的程序来这样的思想,它可以用简单的程序来解决某些复杂的计算问题。解决某些复杂的计算问题。 递归调用在完

47、成阶乘运算、级数运算、幂指数运算等递归调用在完成阶乘运算、级数运算、幂指数运算等方面特别有效。方面特别有效。 在执行递归操作时,在执行递归操作时,C#语言把递归过程中的信息保存语言把递归过程中的信息保存在堆栈中。如果无限循环地递归,或者递归次数太多,则在堆栈中。如果无限循环地递归,或者递归次数太多,则产生产生“堆栈溢出堆栈溢出”错误。错误。 例:用递归方法求阶乘。利用的数学公式为例:用递归方法求阶乘。利用的数学公式为n!=n*(n-1)!。当。当n=0时,时,n!=1。 代码如下:代码如下: public long F(long n) if (n=0|n=1) return 1; else r

48、eturn n*F(n-1); 6.5 属性属性6.5.1 属性的声明属性的声明 格式:格式: 属性修饰符属性修饰符 属性的类型属性的类型 属性名称属性名称方法声明方法声明 说明:若属性是静态成员,通过说明:若属性是静态成员,通过“类名类名.属性成员名属性成员名”访问;若属性是非静态成员,通过访问;若属性是非静态成员,通过“对象名对象名.属性成员属性成员名名”访问。访问。 通过访问器,类的属性成员可以返回一个值(通过访问器,类的属性成员可以返回一个值(get访访问器),或者接受外界通过赋值语句提供的值(问器),或者接受外界通过赋值语句提供的值(set访问访问器)。器)。get访问器访问器 格式

49、:格式: get 语句语句 说明:说明:get访问器中的语句主要是用访问器中的语句主要是用return语句返回某一个变语句返回某一个变量成员的值。量成员的值。 例:例:class Circle protected int page=2; public int pa get return page; class Test static void Main( ) Circle MyCircle=new Circle( ); int n=MyCircle.pa*10; /读读pa属性属性 int m=MyCircle.page*10; /错误!错误!Page是是protected set访问器访问器

50、 格式:格式: set 语句语句 说明:说明:set访问器用于外界写入的值。访问器用于外界写入的值。set访问器就像带有一访问器就像带有一个参数的方法,这个参数的名字是个参数的方法,这个参数的名字是value(注意:参数注意:参数value是隐含是隐含的,不能再定义),它的值就是调用者要写入属性的值。的,不能再定义),它的值就是调用者要写入属性的值。 例:例:class Circle protected int page; public int pa get return page; set page=value; class Test static void Main( ) Circle M

51、yCircle=new Circle( ); MyCircle.pa=10; / 对对pa属性进行写操作属性进行写操作 int n=MyCircle.pa*10; /读读pa属性属性 Console.WriteLine(“n=0”,n); 运行结果如下:运行结果如下: 通过属性来设置变量成员的值,可以在访问器中加入代码,通过属性来设置变量成员的值,可以在访问器中加入代码,以判断数据的合法性。以判断数据的合法性。 例:以下是使用条件运算符进行运算,从而保证类例:以下是使用条件运算符进行运算,从而保证类ClassA的的nIndex不为不为负数。负数。 class A private int nIn

52、dex; public int Index get return nIndex; set nIndex=value=0?value:0; class Teststatic void Main() A p=new A(); p.Index=-9; Console.WriteLine(p.Index); 运行结果如下:运行结果如下: 属性定义可以包含属性定义可以包含get和和set两个访问器的定义,两个访问器的定义,也可以只包含其中的一个。根据也可以只包含其中的一个。根据get和和set访问器的存访问器的存在或不存在,属性按下面特征进行分类:在或不存在,属性按下面特征进行分类: .既包括既包括ge

53、t访问器也包括访问器也包括set访问器的属性被称为读访问器的属性被称为读写写 属性。属性。 .只包括只包括get访问器的属性被称为只读属性。一个只读访问器的属性被称为只读属性。一个只读 属性被赋值是错误的。属性被赋值是错误的。 .只包括只包括set访问器的属性被称为只写属性。访问器的属性被称为只写属性。 属性与变量都可以用来表示事物的状态,但属性可以属性与变量都可以用来表示事物的状态,但属性可以实现只写或只读并且可以对用户指定的值(实现只写或只读并且可以对用户指定的值(value)进行)进行有效性检查,从而保证只有正确的状态才会得到设置,而有效性检查,从而保证只有正确的状态才会得到设置,而变量

54、不能。所以,在变量不能。所以,在C#中一般采取以下中一般采取以下原则原则: (1)若在类的内部记录事物的状态信息,则用变量。)若在类的内部记录事物的状态信息,则用变量。 (2)变量一般用)变量一般用private修饰,以防止对外使用。修饰,以防止对外使用。 (3)对外公布事物的状态信息,则使用属性。)对外公布事物的状态信息,则使用属性。 (4)属性一般与某个或某几个变量有对应关系。)属性一般与某个或某几个变量有对应关系。 索引器是这样一个成员:它能够让对象以类似数组的方索引器是这样一个成员:它能够让对象以类似数组的方式来访问,即可以使对象能用下标来得到一个值,它以访问式来访问,即可以使对象能用

55、下标来得到一个值,它以访问数组的方法来访问类的数据成员,而实际的读数组的方法来访问类的数据成员,而实际的读/写操作则是写操作则是通过通过get和和set来完成的。来完成的。 6.6.1 索引的定义与使用索引的定义与使用 格式:格式: 修饰符修饰符 类型名类型名 this参数列表参数列表 set get 说明:在说明:在set方法中,可以使用一个特殊变量方法中,可以使用一个特殊变量value,用以表,用以表示用户指定的值,而示用户指定的值,而get方法使用方法使用return返回所得到的值。返回所得到的值。 6.6 索引指示器索引指示器例:定义索引指示器例:定义索引指示器class MyInde

56、xer private string myArray=new string4; public string thisint index get if(index=4) return null; else return myArrayindex; set if(!(index=4) myArrayindex=value; 注意:属性可以是静态成员,而索引指示器只能是实例成员。注意:属性可以是静态成员,而索引指示器只能是实例成员。 6.6.2 6.6.2 使用索引指示器访问对象使用索引指示器访问对象 使用索引指示器,可以像数组一样访问类使用索引指示器,可以像数组一样访问类的对象,只不过通过数组下标

57、访问的是存储在数的对象,只不过通过数组下标访问的是存储在数组中的数组元素,而索引指示器访问的是类的对组中的数组元素,而索引指示器访问的是类的对象。象。 使用使用“常规的常规的”C#C#数组,下标数字必须是数组,下标数字必须是整型值。索引器的一个优点就是程序员可以定义整型值。索引器的一个优点就是程序员可以定义整型和非整型两种下标。整型和非整型两种下标。例:例:using System; class Index string name=new stringA,B,C,D; int i; public int thisstring idx get for(i=0;iname.Length;i+) i

58、f(idx=namei) break; if(i=name.Length) return -1; else return i+1; static void Main() Index a=new Index(); if(aA!=-1) Console.WriteLine(字符字符A是序列中的第是序列中的第0个字符个字符,aA); else Console.WriteLine(序列中没有该字符序列中没有该字符); 运行结果如下:运行结果如下: 委托,顾名思义,就是中间代理人的意思。通俗委托,顾名思义,就是中间代理人的意思。通俗地说,委托是一个可以引用方法的对象,即是说委托地说,委托是一个可以引用方

59、法的对象,即是说委托可以调用它所指向的方法。可以调用它所指向的方法。 事件是建立在委托基础上的另一个重要特性。从事件是建立在委托基础上的另一个重要特性。从本质上说,事件就是当某个事情发生时,会自动去执本质上说,事件就是当某个事情发生时,会自动去执行一些语句。事件是特殊化的委托,委托是事件的基行一些语句。事件是特殊化的委托,委托是事件的基础。础。6.7 委托和事件委托和事件6.7.1 委托委托 C#中使用委托的具体的步骤是:中使用委托的具体的步骤是: (1) 声明一个委托,其参数形式一定要和想要声明一个委托,其参数形式一定要和想要 包含的方法的参数形式一致。包含的方法的参数形式一致。 (2) 定

60、义所有你要定义的方法,其参数形式和定义所有你要定义的方法,其参数形式和 第一步中声明的委托对象的参数形式必须第一步中声明的委托对象的参数形式必须 相同。相同。 (3) 创建委托对象并将所希望的方法包含在该创建委托对象并将所希望的方法包含在该 委托对象中。委托对象中。 (4) 通过委托对象调用包含在其中的各个方法。通过委托对象调用包含在其中的各个方法。步骤步骤1: 声明一个委托声明一个委托 格式:格式: 修饰符修饰符 delegate 返回类型返回类型 委托名委托名(参数列表参数列表); 例:例: 委托的声明委托的声明 public delegate void MyDelegate1(strin

61、g input); public delegate double MyDelegate2( ); 声明一个委托的对象,与声明一个普通类对象的方式一样:声明一个委托的对象,与声明一个普通类对象的方式一样: 委托名委托名 委托对象名;委托对象名; 委托对象的声明。委托对象的声明。 MyDelegate1 a; MyDelegate2 b; 步骤步骤2:定义方法,其参数形式和步骤:定义方法,其参数形式和步骤1中声明的委托对象的必中声明的委托对象的必 须相同。须相同。例:定义方法例:定义方法class MyClass1 public void dMethod1(string input) Consol

62、e.WriteLine(“Method1传递的参数是传递的参数是 0,input); public void dMethod2(string input) Console.WriteLine( Method1传递的参数是传递的参数是 0,input); 步骤步骤3:创建一个委托对象并将上面的方法包含其中:创建一个委托对象并将上面的方法包含其中 例:在委托对象中包含方法。例:在委托对象中包含方法。 MyClass1 c2=new MyClass1(); MyDelegate1 d1; d1 = new MyDelegate1(c2.dMethod1); MyDelegate1 d2 = new

63、MyDelegate1(c2.dMethod2); 步骤步骤4:通过委托对象调用包含在其中的方法。:通过委托对象调用包含在其中的方法。 例:调用委托对象包含的方法。例:调用委托对象包含的方法。 d1(abc); d2(123);下面这个例子就是将上面的下面这个例子就是将上面的4个步骤合在一起:个步骤合在一起:using System;public delegate void MyDelegate1(string input); class MyClass1 public void dMethod1(string input) Console.WriteLine(dMethod1传递的参数是传递

64、的参数是 0,input); public void dMethod2(string input) Console.WriteLine( dMethod2传递的参数是传递的参数是 0,input); class Driver static void Main() MyClass1 c2=new MyClass1();? MyDelegate1 d1 = new MyDelegate1(c2.dMethod1);? MyDelegate1 d2 = new MyDelegate1(c2.dMethod2);? d1(abc); d2(123); 运行结果如下:运行结果如下: 委托是可以合并的,又

65、称为多播(委托是可以合并的,又称为多播(Multicast)。合并的委托实)。合并的委托实际上是对多个方法的调用,对这样的委托的调用,实际上是对所包际上是对多个方法的调用,对这样的委托的调用,实际上是对所包装的各个方法的全部调用,其中的多个方法又称为该委托的调用列装的各个方法的全部调用,其中的多个方法又称为该委托的调用列表。表。 对于多个相同类型的委托,可以用加号运算符对于多个相同类型的委托,可以用加号运算符“+”进行调用列进行调用列表的合并,可以用减号运算符表的合并,可以用减号运算符“-”移除其调用列表中的方法。移除其调用列表中的方法。 委托加减运算后的结果,如果其中不包含方法,则结果为委托

66、加减运算后的结果,如果其中不包含方法,则结果为null。 例:例: strMod a=new strMod(DelegTest.reSpace); strMod b=new strMod(DelegTest.delSpace); strMod c=a+b; c(“How are you!”); /先调用先调用reSpace()方法,再调用方法,再调用delSpace()方法方法 c-=a; c-=b; /这时这时c的值为的值为null 6.7.2 事件事件 事件是建立在委托基础上的另一个重要特性。其事件是建立在委托基础上的另一个重要特性。其工作过程如下:关心某事件的对象向事件中注册事件工作过程

67、如下:关心某事件的对象向事件中注册事件处理程序,当事件发生时,会调用所有已注册的事件处理程序,当事件发生时,会调用所有已注册的事件处理程序。事件处理程序要用委托来表示。处理程序。事件处理程序要用委托来表示。 1.事件的声明事件的声明 事件是类成员,以关键字事件是类成员,以关键字event 声明。声明。 格式:格式: 修饰符修饰符 event 委托名委托名 事件名;事件名; 例:例:delegate void MyEventHandler(); 事件变量的声明为:事件变量的声明为: class MyEvent public event MyEventHandler activate; /acti

68、vate就是一个事件名就是一个事件名 2. 事件的预订与撤消事件的预订与撤消 事件的预订就是向委托的调用列表中添加方法,是通过为事件加上事件的预订就是向委托的调用列表中添加方法,是通过为事件加上运算符运算符+=来实现的。来实现的。 格式:格式: 事件名事件名+=new 委托名委托名(方法名方法名); 例:例:MyEvent evt=new MyEvent(); evt.activate+=new MyEventHandler(handler); 又例:又例: OkButton.Click += new EventHandler(OkButtonClick); 这样,只要事件被触发,所预定的方法

69、就会被调用。这样,只要事件被触发,所预定的方法就会被调用。 事件的撤消则采用运算符事件的撤消则采用运算符-=来实现:来实现: 格式:格式: 事件名事件名-=new 委托名委托名(方法名方法名); 例:例:OkButton.Click -= new EventHandler(OkButtonClick); 3.事件的发生事件的发生 就是委托的调用列表中的所包含的各个方法就是委托的调用列表中的所包含的各个方法的调用。的调用。 格式:格式: 事件名事件名(参数参数);例:演示事件的声明、事件的预订及撤销、事件的发生。例:演示事件的声明、事件的预订及撤销、事件的发生。using System;dele

70、gate void MyEventHandler(); /为事件建立一个委托为事件建立一个委托class MyEvent public event MyEventHandler activate; /声明一个事件声明一个事件 public void fire() /调用这个方法来触发事件调用这个方法来触发事件 if(activate!=null) activate(); /触发事件触发事件 class Test static void handler() Console.WriteLine(事件发生事件发生); static void Main() MyEvent evt=new MyEven

71、t(); /把方法把方法handler()添加到事件列表中添加到事件列表中 evt.activate+=new MyEventHandler(handler); evt.fire(); /调用触发事件的方法调用触发事件的方法 C#语言中允许各种委托应用于事件中,但在典型语言中允许各种委托应用于事件中,但在典型的应用中,委托的常用格式如下:的应用中,委托的常用格式如下: delegate void 委托名委托名(object sender, EventArgs e); 其中,返回类型为其中,返回类型为void,委托名中有两个参数,委托名中有两个参数,分别表示事件的发出者及事件发生时的一些参数,这

72、分别表示事件的发出者及事件发生时的一些参数,这种典型的情况广泛应用于窗体中处理各种事件。种典型的情况广泛应用于窗体中处理各种事件。 例:事件的典型应用例:事件的典型应用 public delegate void EventHandler(object sender, EventArgs e) public event EventHandler Click; Button okButton=new Button(); okButton.Click+=new EventHandler(okButton_Click); void okButton_Click(object sender, EventArgs e) 本章作业: 1. 习题6的1、2、3、4、5、6、7 。实验报告:实验报告: 实验五实验五

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

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