一章面向对象程序设计课件

PPT
  • 阅读 26 次
  • 下载 0 次
  • 页数 103 页
  • 大小 372.490 KB
  • 2022-11-24 上传
  • 收藏
  • 违规举报
  • © 版权认领
下载文档40.00 元 加入VIP免费下载
此文档由【小橙橙】提供上传,收益归文档提供者,本网站只提供存储服务。若此文档侵犯了您的版权,欢迎进行违规举报版权认领
一章面向对象程序设计课件
可在后台配置第一页与第二页中间广告代码
一章面向对象程序设计课件
可在后台配置第二页与第三页中间广告代码
一章面向对象程序设计课件
可在后台配置第三页与第四页中间广告代码
一章面向对象程序设计课件
一章面向对象程序设计课件
还剩10页未读,继续阅读
【这是免费文档,您可以免费阅读】
/ 103
  • 收藏
  • 违规举报
  • © 版权认领
下载文档40.00 元 加入VIP免费下载
文本内容

【文档说明】一章面向对象程序设计课件.ppt,共(103)页,372.490 KB,由小橙橙上传

转载请保留链接:https://www.ichengzhen.cn/view-44902.html

以下为本文档部分文字说明:

一章面向对象程序设计内容介绍10.1面向对象技术的基本概念10.2类的定义和对象10.3构造函数和析构函数10.4类的属性10.5this引用10.6类的静态数据成员和静态方法10.7类的继承性10.8类的多态性10.9抽象类和抽象方法10.10委托10.11事件10

.12索引指示器10.13接口10.14运算符重载10.15命名空间学习目标掌握面向对象的程序设计思想;掌握类的封装性、继承性和多态性的实现方法;掌握接口、委托与事件的使用方法;掌握运算符重载的方法。10.1面向对象技术的基本概念结构化程序设计的缺点:用此类语言设

计的程序结构清晰,使用方便,但是它将数据和对数据的处理过程分开,一旦数据结构改变,其相关处理过程必须修改,程序可重用性差,这给软件的调试和维护带来了困难。20世纪九十年代,人们提出了面向对象的程序设计思想(OOP,ObjectOrientedProgramming)。面向对象程序设计是C#编程的

核心技术,使得程序的设计更加合理,而且易于维护。OOP技术由5个最基本的概念组成:类(class)、对象(object)、方法(method)、消息(message)和继承(inheritance)。

1.类是对一组具有相似特性的客观事物的抽象,是对事物的特性和功能的描述,这一点体现了类的封装性。封装是一种程序设计机制,它绑定代码及其操作的数据,并使它们不受外界干涉和误用的影响,从而保证安全性。类与传统的模块概念是不同的。模块的层次结构在逻辑上

体现了模块间的功能概括关系,而类的层次结构在逻辑上体现的是类的继承关系,处于上层的类称为父类或基类,处于下层的类称为子类或派生类。电视机黑白电视机彩色电视机CRT彩色电视机液晶彩色电视机等离子彩色电视机图101.1电视机的分类图2.对象对象是类类型的

变量,是类的实例。例如:35英寸康佳液晶彩电;42英寸康佳液晶彩电一个类可以定义多个对象,对象的属性值可以不同,但它们的操作功能是相同的。3.方法方法是指实现对象所具有的操作功能的代码。每个对象一般包含若干种方法,每个方法有方法名和对应的一组代码。方法体现了对象的一种行为

能力,程序通过对象的方法,去获取或修改对象的属性。4.消息客观世界是有各种对象组成的,对象之间存在着联系,对象之间的联系是通过消息激活机制实现的。例如:张先生拿着电视遥控器在看电视,张先生是对象,电视机是对象,电视遥控器也是对象。当张先生按下遥控器的提高

声音的按钮时,张先生就和遥控器之间建立了联系,即张先生向遥控器发出了要求提高声音的消息;遥控器对按钮进行判断(遥控器响应该消息),然后向电视机发出调高声音的信号,此时,遥控器和电视机之间也建立了联系,即遥控器向电视机发出了要求提高声音的消息;电视机接收到信号后经过判断(电视机响应该消息),提高了

音量。从这个例子中可以看出,消息由三部分组成:发送对象、接受对象和消息的内容。在OOP系统中,向一个对象发送消息,就是调用那个对象的某个功能(函数),消息的实质是调用对象的成员函数。同一个对象可以接受不同形式的多个消息,产生不同的响应。同一个消息可以发

送给不同的对象,得到的响应可能是不同的,这一点体现了类的多态性,多态性是OOP的主要特征之一。同时从该例中可以看出,消息也可以传递。5.继承继承指的是一个子类可以从现有的父类中派生出来,子类除了继承父类的特性和功能以外

,还可以增加新的特性和功能。继承描述的是类间的一种层次关系,继承性是OOP的主要特征之一。继承的一个重要作用是实现代码重用,节省程序开发的时间。程序员可以利用现有的类,按照需求修改该类,以得到一个满足要求的新类。例如

程序员可以修改系统预定义的按钮控件,使它的外观呈现出椭圆形。程序员可以重新定义自定义类中从object类中继承来的Equals方法,实现自定义对象的相同判断。10.2类的定义和对象1.类的定义类是一种用户自定义的数据类型。定义格式

为:class类名{访问权限修饰符其他修饰符类成员定义;}常用的访问权限有三种,分别为:private(私有)、public(公有)和protected(保护)其他修饰符包括:static、readonly、const、vi

rtual、override、sealed、abstract和new。readonly表示只读修饰符,其后只能声明数据成员,readonly型数据成员只能在声明时或构造函数中初始化,其它地方不能修改其值。const表示常量修饰符,其后只能声明数

据成员,且只能在声明时初始化,其它地方不能修改其值。如果成员声明前没有访问权限关键字,则默认为private访问权限。10.2类的定义和对象2.对象对象是类的实例(instance),即类的变量。缺省定义

格式为:类名对象名=new类名();定义对象时,才会为对象的每一个实例数据成员在堆中依次分配存储空间。通过对象,可以访问它的公有成员。结构体与类的差异①结构体变量是值类型,而类变量(对象)是引用类型。值类型在栈上分配空间,引用类型在堆上分配空间,所以,结构体变量相互赋值是相同数

据存储在不同的栈空间中,引用类型相互赋值是两个对象引用同一个堆空间数据。②结构体只能从接口继承,不能从结构体继承;类则支持继承和派生。③结构体中不能初始化数据成员;类则可以初始化数据成员。④系统不给结构体提供默认构造函数,但用

户可以显式定义造函数,结构体不提供析构函数;类则支持构造函数和析构函数。⑤结构体没有abstract、sealed和protected修饰符。在表现抽象和多层次的类型时,建议采用类的方法;如果只是存储一些数据和少量逻辑时,建议使用结构实现。【例10-1】定义带有身份证和姓名字段的人员类,

并提供接口函数计算年龄。usingSystem;namespace教材_类和对象{classProgram{staticvoidMain(string[]args){Personp1=newPerson();p1.SetNameId("王宏","320402196312

091234");p1.Display();p1.name="王力宏";//p1.id="320402197908231432";错误,不能通过对象访问其私有成员p1.Display();Console.ReadKey();}}publiccla

ssPerson{//声明字段privatestringid;//可以赋初值,相当于缺省值;不赋初值,则默认为NULLpublicstringname;//可以赋初值,相当于缺省值;不赋初值,则

默认为NULLpublicvoidDisplay(){//可以在成员函数中访问所有数据成员DateTimedate1=DateTime.Now;//获取计算机的当前时间intnowy=date1.Year;strin

gby=id.Substring(6,4);intbyi=int.Parse(by);intage=nowy-byi;Console.WriteLine("身份证号:{0},姓名:{1},年龄:{2}",id,name,age);}pub

licvoidSetNameId(stringpname,stringpid){name=pname;id=pid;}}}10.3构造函数和析构函数1.构造函数构造函数是一种特殊的成员函数,它的函数名与类名相同

,无返回类型。构造函数是在定义对象时自动调用的。构造函数与9.5节的普通函数一样,也可以进行重载,以实现对象的多种初始化方法。2.析构函数对象和其他变量一样,都有生命周期;生命周期结束时,这些变量和对象就要被

撤销。对象撤销时,系统自动调用其析构函数,并释放其占用的堆空间。析构函数的名字为~类名,无参数,无返回类型,也无任何修饰符。析构函数不能重载。10.4类的属性如何修改对象的private字段呢?除了可以通过public接口函数,设置和读取private字段的方法外,C#还提供

了“属性”的方法进行private字段的设置和读取。“属性”总是和某个或某些字段相关联。“属性”本质上属于类的成员函数,提供set和get访问器,用于对其关联字段进行设置和读取,同时在set和get访问器中,

可以根据程序逻辑,限制用户的设置和读取操作。“属性”与字段的区别:定义对象时,系统为对象的实例字段分配存储空间,属性不会分配存储空间,属性本质上是方法。字段用小写字母定义,属性以大写字母定义。属性定义格式:修饰符数据类型名属性名{set{//设

置关联字段的值}get{//获取关联字段的值}}数据类型名应与属性关联字段的类型名相同。“属性”分为只读属性、只写属性和读/写属性。只读属性只带get访问器,只写属性只带set访问器,读/写属性带get访问器和set访问器。例如:DateTime的Now属性是只读属性

注意:一个属性的get访问器和set访问器必须在属性的声明中一次性定义,不能分开定义。为了简化代码,C#3.5提供了自动属性的概念,即类不需要显式提供关联字段,而是由编译器自动提供私有关联字段。利用类的属性,可以减少修改字段的公有接口函数的定

义。10.5this引用系统为每一个实例方法,提供了一个隐含的this参数,其引用调用该方法的对象,在方法内部,通过this,确定数据成员的归属问题。“this”是一个const型变量,只能使用,不能改变其值。当方法内的临时变量与数据成员同名时,需要在同名数据成员前显式加上this。10.6类的

静态数据成员和静态方法1.类的静态数据成员“静态数据成员”:“static”修饰符在定义对象时,要对其每一个实例成员分配存储空间。同一个类的不同对象,其实例数据成员占用不同的存储空间,访问方法为“对象.实例数据成员”。类的静态数据成

员是该类的所有对象共享的,其访问方法为“类.静态数据成员”。2.类的静态方法在定义类的方法时,若在其声明前加“static”修饰符,则该方法为“静态方法”,不加“static”修饰符的方法为实例方法。静态方法只能访问

该静态方法所在类的静态数据成员和静态方法。实例方法可以访问所有成员。如:System.Array的Sort、Reverse、Find等3.静态方法不含有this引用,所以通常要将实例对象作为参数传递到static方法中

,实例方法中含有this引用,其所获取的实例成员值是该对象特有的。【例10-5】用静态方法和静态数据成员实现对象个数的统计和显示。usingSystem;namespace教材_静态成员函数{classProgram{staticvoidMai

n(string[]args){stringoutput;Personp1=newPerson();p1.Id="320402198412302323";p1.Name="张飞";p1.Sex="男";p1.Display();Personp2=newPer

son("320403198712121234","王军霞","女");p2.Display();Person.ReportCount();//只能通过类名访问静态成员Console.ReadKey();}}}publicclassPerson{privatestring

id;//不赋初值,则默认为NULLprivatestringname;//相当于类的全局变量,可以通过类名使用,每次增加一个对象,总人数加1publicstaticinttotalcount;publicstringId

{get{returnid;}set{if(value.Length!=18)return;id=value;}}publicstringName{get{returnname;}set{name=value;}

}publicstringSex{set;get;}publicPerson()//每次增加一个对象,人数加1{id="未知";name="未知";Sex="未知";totalcount++;}publicPerson(stringpid,s

tringpname,stringpsex)//每次增加一个对象,人数加1{id=pid;name=pname;Sex=psex;totalcount++;}~Person()//每次结束一个对象,人数减1{totalcount--;Console.Write

Line(name+"使用完毕,"+"还有"+totalcount+"人在使用");Console.ReadKey();}publicstaticvoidReportCount()//在static函数内,只能使用静态成员

;{Console.WriteLine("目前总人数为:{0}",totalcount);}publicvoidDisplay(){Console.WriteLine("身份证号:{0},姓名:{1},性别:{2}.",id,na

me,Sex);}}10.7类的继承性类的三大特性是封装性、继承性和多态性。继承性指的是可以从一个或多个基类派生出一个新类,新类继承了基类的非私有成员,同时,新类又可以根据需要定义新的成员或重写从基类处继承的成员。派生

类定义格式为:Class派生类名:基类名{派生类成员定义;}关于C#中的继承,有以下几点说明:C#只支持单一继承,即只能直接从一个基类处继承。若需要有多个直接基类(多重继承),采用接口的方法实现。继承是可传递的。如果从A派生出B,又从B派生出C,则

C既继承了B的成员,又继承了A的成员。由于所有类的根基类是object类,所以,所有类都包含从object类继承来的Equals、GetType、ToString公有方法。基类的构造函数和析构函数都不能被继承,其它

成员都可以被继承。在派生类中,可以直接使用基类的protected和public成员,但不能直接使用基类的private成员,可以通过基类的public成员函数访问基类private成员。在声明派生类构造函数时,必须正确调用基类构造函数,若不显式调用基类构造函

数,则按基类的缺省构造函数调用。若基类不提供缺省构造函数,则编译错误。在派生类中,可以采用new修饰符,重写基类的非virtual成员函数,以达到在派生类中屏蔽基类中非virtual成员函数的作用。在派生类中,可以采用override修饰符,覆盖基类的virtual成员函数,以实

现类的多态性。派生类对象可以赋给基类对象。成员查找路径:通过派生对象调用public成员时,首先在派生类中查找,若找不到,再到直接基类中查找,若还不存在,则继续沿着继承层次向更上一层的基类中查找,直到查找到为止。【例10-6】用继承实

现学生、工作人员和一般人员的定义和使用。usingSystem;namespace教材_继承{classProgram{staticvoidMain(string[]args){Personp1=newPerson("

320402197812121234","小刘","男");p1.Display();//调用基类的Display()方法Console.WriteLine();Students1=newStudent("320402199308311423

","汪兰","女","大一");s1.Display();//调用派生类的Display()方法s1.Name="马援";//修改从基类中继承的公有属性值s1.UpdateGrade("大二");//调用派生类新增的方法,修改其新增字段sclasss1.Display(

);//调用派生类的Display()方法workerw1=newworker("320402196305011423","蒋大为","女",9800);w1.Display();//调用派生类的Display()方法w1

.Wage=9000;//修改派生类的新增属性Wagew1.Sex="男";w1.Display();//调用派生类的Display()方法Console.ReadKey();}}}publicclassPerson{privatestringid;publicst

ringname;publicstringSex//定义自动属性,编译器自动提供关联私有字段{get;set;}publicstringName{get{returnname;}set{name=va

lue;}}publicvoidDisplay(){Console.Write("身份证号:{0},姓名:{1},性别为:{2}",id,name,Sex);}publicPerson(stringpid,stri

ngpname,stringpsex){name=pname;id=pid;Sex=psex;}}classStudent:Person{stringsgrade;//增加私有字段年级publicstringSgrade{get

{returnsgrade;}set{sgrade=value;}}publicvoidUpdateGrade(stringpgrade){sgrade=pgrade;}publicStudent(st

ringpid,stringpname,stringpsex,stringpgrade):base(pid,pname,psex)//base为关键字,派生类的构造函数中必须提供基类构造函数的调用,否则,按缺省方法调用{sgrade=pgrade;}newpublicvoidDispla

y()//new为修饰符,重写基类中的非虚相同方法{base.Display();//调用基类中的方法Console.WriteLine("年级为:"+sgrade);}}classWorker:Person{intw

age;//增加私有字段工资publicintWage{get{returnwage;}set{wage=value;}}publicvoidUpdateWage(intpwage){wage=pwage;}publicWorker(stringp

id,stringpname,stringpsex,intpwage):base(pid,pname,psex){wage=pwage;}newpublicvoidDisplay(){base.Display();Console.Wri

teLine("工资为:"+wage);}}10.8类的多态性多态性指同一消息作用于不同的对象时,能够有不同的响应。C#支持两种类型的多态性:静态多态和动态多态。静态多态:通过方法重载来实现的,对象调用若干同名方法

,系统在编译时,根据调用方法的参数个数、类型或顺序确定调用哪个同名方法,实现何种操作。动态多态:通过虚函数实现的,程序运行时,根据基类对象所具体引用的派生对象,调用派生对象的覆盖虚函数,实现不同的操作。静态多态与动态多态的区别:静态多态是在编译

期间完成的,因此执行速度快;动态多态是在程序运行期间完成的,因此执行速度较慢,但它提高了程序的灵活性和抽象层次,使软件的可扩充性增强。基类中虚函数定义格式为:publicvirtual返回类型虚函数名(参数列表){函数体}派生类中

覆盖虚函数定义格式为:publicoverride返回类型虚函数名(参数列表){函数体}必须注意:派生类中的覆盖虚函数必须和基类中虚函数的函数名,返回类型,参数个数及类型完全一致。static不能和virtual、override修饰符同时使用。因为虚函数的本质是实现动

态多态性,通过运行时,基类对象所引用的派生对象,达到调用覆盖虚函数的目的。而static函数是通过类名进行调用,与对象无关。在一个类的继承体系中,可以采用sealedoverride的方法修饰一个虚函数,禁止后续派生类继续覆盖该虚函数。sealed(密封)不

能修饰非虚函数。【例10-7】用虚函数实现各类人员的显示。usingSystem;namespace教材_多态性{classProgram{staticvoidMain(string[]args){Person[]personarray=newPerson[4];/

/定义Person基类数组//派生对象可以赋给基类对象personarray[0]=newStudent("320402199005011234","李刚","男","研一");personarray[1]=newWorker("32

0402199010101234","李魁","男",6700);personarray[2]=newWorker("320402196312091234","彭","女",2800);personarray[3]=newPerson("320402197809091234","

彭桃","女");foreach(Persontpinpersonarray){tp.Display();}Console.ReadKey();}}}publicclassPerson{privatestringid;

publicstringname;publicstringSex{get;set;}publicstringName{get{returnname;}set{name=value;}}publicstringId{get{returnid;}}publicvirtual

voidDisplay()//virtual为修饰符,定义虚函数{Console.WriteLine("身份证号:{0},姓名:{1},性别为:{2}",Id,Name,Sex);}publicPer

son(stringpid,stringpname,stringpsex){name=pname;id=pid;Sex=psex;}}publicclassStudent:Person{stringsg

rade;//增加私有字段publicstringSgrade{get{returnsgrade;}set{sgrade=value;}}publicvoidUpdateGrade(stringpgr

ade){sgrade=pgrade;}publicStudent(stringpid,stringpname,stringpsex,stringpgrade):base(pid,pname,psex){sgrade=pgrade;}publicoverridevoidDisplay

()//override为修饰符,覆盖基类中的相同虚函数{Console.WriteLine("身份证号:{0},姓名:{1},性别为:{2},年级为:{3}",Id,Name,Sex,Sgrade);}}publiccla

ssWorker:Person{intwage;publicintWage{get{returnwage;}set{wage=value;}}publicvoidUpdateWage(intpwage){wage=pwage;}publicWorker(stringpid,strin

gpname,stringpsex,intpwage):base(pid,pname,psex){wage=pwage;}publicoverridevoidDisplay(){Console.WriteLine("身份证号:{0},姓名:{1},性别为

:{2},工资为:{3}",Id,Name,Sex,wage);}}【例10-8】用虚函数和非泛型集合实现各类人员列表的数据处理。usingSystem;usingSystem.Collections

;//非泛型集合命名空间using教材_多态性;namespace教材_多态性_非泛型集合{classProgram{staticvoidMain(string[]args){ArrayListpersonlist=newArrayList();personlist.

Add(newStudent("320402199409123456","蒋韵","女","大一"));personlist.Add(newWorker("320402199312091234","李威","男",2700));personlist.Add(newWorker("3204

02197310011234","李香","女",15000));Console.WriteLine(personlist.Capacity);Console.WriteLine(personlist.Count);foreach(Objecttpinpersonlist){i

f(tp.GetType()==typeof(Student)){((Student)tp).Sgrade="大二";}else{if(((Worker)tp).Wage<3500)((Worker)tp).Wage=3500;}}foreach(Persontpinperso

nlist){tp.Display();}Console.ReadLine();}}}10.9抽象类和抽象方法1.抽象类抽象类表示一种抽象的概念,用作派生类的基类,以便所有其派生类具有相同的数据成员和函数成员。抽象类的定义格式为:abstractc

lass类名{访问权限修饰符其他修饰符类成员定义;}2.抽象方法抽象方法的定义格式为:publicabstract返回类型函数名(参数列表)抽象方法描述的是成员函数的定义,而非实现,所以它没有函数体部分

。关于抽象类和抽象方法必须注意以下几点:含有抽象方法的类,一定是抽象类。但抽象类并非一定要包含抽象方法,即抽象类中可以定义带实现的方法。抽象类只能作为派生类的基类,不能被实例化。不能同时使用Abstract和sealed修饰符声明

抽象方法,因为抽象方法需要在派生类中被覆盖,而sealed修饰符禁止方法被覆盖。抽象方法逻辑上类似于虚方法,可以在派生类中被覆盖。从抽象类派生出的派生类,若全部覆盖了从抽象类中继承来的抽象方法,该类可以声明为非抽象类,能够实例化,否则,

仍然为抽象类。【例10-9】用抽象图形类实现矩形、圆等图形周长的求解。usingSystem;namespace教材_抽象类{classProgram{staticvoidMain(string[]a

rgs){squaref1=newSquare(20,10);circlef2=newCircle(30,30,15);Console.WriteLine(f1.Perimeter());Console

.WriteLine(f2.Perimeter());Console.ReadKey();}}}publicabstractclassFigure{publicabstractfloatPerimeter();}

publicclassSquare:Figure{privatefloatlength,width;publicSquare(floatplength,floatpwidth){length=plength;width=pwidth;}publicoverridefloat

Perimeter(){return2*(length+width);}}publicclassCircle:Figure{privatefloatxc,yc,radium;publicCircle(f

loatpxc,floatpyc,floatpradium){xc=pxc;yc=pyc;radium=pradium;}publicoverridefloatPerimeter(){return(float)(2

*3.14*radium);}}10.10委托委托是C#语言提供的新的引用类型,即委托类型,也称代理类型。在功能上类似于C语言的函数指针,目的是通过委托类型对象去调用相同签名的函数。委托是从system.delegate中派生的,因此是类型安全的。采用委托可以实现通用程序

的编写。委托的操作步骤:1.定义委托类型2.定义委托对象3.定义委托方法的实现4.委托的调用委托的定义步骤1.定义委托类型委托类型定义格式为:修饰符delegate函数返回类型委托类型名(函数形参列表)例如:publi

cdelegatebooldtest(Personp,strings);表示定义了一个委托类型,它能代表第一个参数为Person对象,第二个参数为string类型,返回值为bool类型的函数。委托的定

义步骤2.定义委托对象委托对象定义格式为:委托类型名委托对象名=new委托类型名(委托方法名);其中委托方法名可以是某个类的静态方法名,也可以是某个对象的实例方法名。方法的参数类型、返回类型必须与委托类型名的要求一致。例如:dtestd1=ne

wdtest(Find.FindPeopleById);表示将委托对象d1代表Find类的FindPeopleById静态方法。具体见下面的例10-10。以后就可以通过调用d1来达到调用FindPeopleById函数的目的。委托的定义步骤3.定义委托方法的实现委托方法是真正要调

用的函数,根据逻辑需要,在类中定义其实现过程。例如:publicstaticboolFindPeopleById(Personp,strings){returnp.Id==s;}委托的定义步骤4.委托的调用格式为:委托对象名(实参列表);

例如:d1(p1,"320402196312091234");委托类型案例下面结合10-7案例中的类,学习委托类型的使用。【例10-10】用委托实现各类人员的身份查找和性别查找。usingSystem;using教材_多态性;//引用了多态性的类

publicdelegatebooldtest(Personp,strings);//委托类型必须在类外定义,最好定义在命名空间外namespace教材_委托{classProgram{staticvoidMain(string[]args){Person[]

personarray=newPerson[4];personarray[0]=newStudent("320402199005011234","李刚","男","研一");personarray[1]=newWork

er("320402199010101234","李魁","男",6700);personarray[2]=newWorker("320402196312091234","彭","女",2800);personarray[3]=n

ewPerson("320402197809091234","彭桃","女");dtestd1=newdtest(Find.FindPeopleById);//定义委托对象d1inti=0;foreach(Persontp

inpersonarray){i++;//在遍历数组时,找到身份为"320402196312091234"的人就退出遍历if(d1(tp,"320402196312091234"))break;}personarray[i-1].Display();i=0;d1=

newdtest(Find.FindPeopleBySex);//将委托对象代表FindPeopleBySex函数foreach(Persontpinpersonarray){i++;if(d1(tp,"男"))break;//遍历数组时,找到性别为"男"的第一人

就退出遍历}personarray[i-1].Display();Console.ReadKey();}}classFind//定义查找类,提供人员的各种查找方法{publicstaticboolFindPeopleById(Personp,s

trings){returnp.Id==s;}publicstaticboolFindPeopleBySex(Personp,strings){returnp.Sex==s;}}【例10-11】用委托实现学生泛型集合中女同学的查

找。usingSystem;usingSystem.Collections.Generic;using教材_多态性;namespace教材_委托_泛型{classProgram{staticvoidMain(string[]args){List

<student>myList=newList<student>();//定义学生泛型集合对象myList.Add(newStudent("320402199005011234","李刚","男","研一"));myList.Add(newStudent("320402199201014321

","王君","女","博一"));myList.Add(newStudent("320402200009095678","向日葵","女","小六"));List<Student>sl=myLis

t.FindAll(FindStudentByMale);//调用FindAll,查找所有女生foreach(Studentsinsl)s.Display();Console.ReadLine();}publicstaticboolFindStuden

tByMale(Studentp)//定义查找条件{returnp.Sex=="女";}}10.11事件事件就是当对象或类的状态发生改变时,对象或类发出的消息。事件是C#内置的语法,用户可以定义和处理事件。在C#中,事件是委托类型变量,可

以代表事件的处理函数。事件的分类:事件分为窗体事件(窗体状态改变)、键盘事件(用户单击键盘)、鼠标事件(用户操作鼠标)、COMMAND事件(用户操作菜单)、用户自定义事件等。C#事件用作对象之间的通信,发送状态改变消息的对象称为事件源,对事件进行处理的对象称为接

收者。在事件源中定义事件,定义事件的触发方式;在事件接收者中定义事件响应函数的实现,并将该响应函数与事件源的事件进行关联;当有事件发生时,系统自动调用该事件的响应函数。事件的定义步骤。1.定义一个事件委托2.在事件源中定

义一个事件3.在事件源中定义事件的触发方式4.在事件接收者中定义事件的响应函数5.在事件接收者中设置事件响应函数,也称为事件的预订1.定义一个事件委托publicdelegatevoidEventHandler(objectsender,EventArgse)EventHandler是事件委托

名,用户可以自己定义名称。事件委托的定义格式是固定的,返回值为void型,第一个参数表示事件源对象,第二个参数是用于描述事件附加信息的对象,它必须是EventArgs类的派生类,若事件发生时不需要向事件处理程序传递附加信息,就直接使用EventArgs类的对象。事件不同,所附加的信息也不同

,鼠标事件的附加信息为鼠标位置,键盘事件的附加信息为按键的ASCII码值。EventArgs类包含在System命名空间中。2.在事件源中定义一个事件如:publiceventEventHandlerC

hanged;event是定义事件的关键字,事件名为Changed。3.在事件源中定义事件的触发方式如:在设置姓名时,触发事件Set{…..OnChanged(e);//设置事件触发方式,并响应事件}publicvirtualvoidOnChang

ed(EventArgse){if(Changed!=null){Changed(this,e);}//this表示事件源对象本身,e表示事件附加信息对象}4.在事件接收者中定义事件的响应函数如:staticvoidPersonChanged(object

sender,EventArgse){……//事件响应处理代码}5.在事件接收者中设置事件响应函数,也称为事件的预订如:P1.Changed+=newEventHandler(PersonNameChanged);【例10

-12】用事件实现修改人员姓名时报告该人的老名字和新名字。usingSystem;//定义事件的附加信息类,产生事件时,会将事件发送方(人员)的新旧名字传递给接收方publicclassMyEventArgs:System.EventArgs

{privatestringnewname;privatestringoldname;publicstringNewName{get{returnnewname;}set{newname=value;}}publicstringOldName{get{returno

ldname;}set{oldname=value;}}}publicdelegatevoidEventHandler(objectsender,MyEventArgse);//定义事件委托namespac

e教材_事件{classProgram{staticvoidMain(string[]args){Personp1=newPerson("320401199011113456","王贝");//设置p1的Chan

ged事件响应函数为PersonNameChangedp1.Changed+=newEventHandler(PersonNameChanged);p1.Name="理想";//改变p1的Name属性值,

产生Changed事件Personp2=newPerson("320402199912126789","李栏");//设置p2的Changed事件响应函数为PersonNameChangedp2.Chan

ged+=newEventHandler(PersonNameChanged);p2.Name="张飞";Console.ReadKey();}//定义事件的响应函数staticvoidPer

sonNameChanged(objectsender,MyEventArgse){Console.WriteLine(e.OldName+"改名为"+e.NewName);}}publicclassPerson{publiceventEventHandlerChanged;

//定义事件privatestringid;privatestringname;publicstringName{get{returnname;}set{MyEventArgse=newMyEventArgs();//定义事件附加信息对象,并设置事件的附加信息e

.OldName=name;name=value;e.NewName=value;OnChanged(e);//触发事件}}publicPerson(stringpid,stringpname){name=pname;id=pid;

}publicvirtualvoidOnChanged(MyEventArgse){if(Changed!=null)//如果用户设置了该事件的响应处理函数Changed(this,e);//执行事件的响应处理函数}}}10.12索引指示器在C#语

言中,数组、字符串和集合都是类,如定义一个字符串对象,strings1="students",则可以采用索引的方式获取字符串的每一个字符,s1[3]表示字符'd'。如定义一个泛型集合List<int>l1=newList<int>(

),l1.Add(13),l1.Add(45),则l1[0]表示13,l1[1]表示45,集合也可以采用索引的方式获取集合中存储的数据。同样,对于用户自定义类,只要在类中定义了索引指示器(indexer)

,就可以采用索引的方式方便地访问类的数据成员.索引指示器的定义类似于类的属性,提供set和get访问器,且索引指示器可以带参数。索引指示器定义格式为:修饰符数据类型名this[参数列表]{set{//设置数据}get{//获取数据}}this是定义索引指示器的

关键字,索引指示器的参数定义必须放在[]中描述,且至少有一个参数,数据类型名为通过索引获取的数据成员的类型。索引指示器不能为static,因为索引一定要通过对象使用。同属性一样,索引也分为只读索引(如string类型的索引)和读/写索引【案例】通过索引访问一个工作人员的家庭电话、单位电话和手机号码

。usingSystem;namespace教材_索引{classProgram{staticvoidMain(string[]args){Workerw1=newWorker("320402196305011423","蒋大为"

,"女",9800);w1[0]="051985192345";//通过索引设置家庭电话w1[1]="051985191955";//通过索引设置单位电话w1[2]="13915016778";//通过索引设置手机号码

w1.Display();Console.ReadKey();}}}{...此部分的代码为10-6教材_继承案例中,Person类的代码部分...}publicclassWorker:Person{string[]telephon

e=newstring[3];//添加string数组,用于存储电话号码publicstringthis[inttpindex]{set{telephone[tpindex]=value;}get{returntele

phone[tpindex];}}intwage;publicintWage{get{returnwage;}set{wage=value;}}publicvoidUpdateWage(intpwage){wage=pwage;}publicWorker(stringpid,stri

ngpname,stringpsex,intpwage):base(pid,pname,psex){wage=pwage;}newpublicvoidDisplay(){base.Display();Console.WriteLine

("工资为:"+wage);Console.WriteLine("家里电话:{0},单位电话:{1},手机:{2}",telephone[0],telephone[1],telephone[2]);}}10.13接口接口(interface)简单

理解就是一种规范,是一组行为规范,使得继承接口的类或结构在形式上保持一致。接口是引用类型。接口中只能包含方法、属性、索引器和事件四种成员,并且不提供它们的实现。方法的实现是在继承接口的类中完成的。接口本质上可以看作是一

个定义了抽象方法的类,该类仅提供了方法的定义,而没有方法的实现,方法的具体实现由接口的派生类来完成。接口是实现抽象机制的重要手段,通过接口实现可以部分的弥补继承和多态在纵向关系上的不足,通过接口实现,同一个对象可以有不同的身份,以达到

多态性要求。在使用面向接口的编程过程中,将具体逻辑与实现分开,减少了各个类之间的相互依赖,当需求变化时,不需要对已经编写的系统进行改动,添加新的实现类就可以了,对系统的其他模块不会造成影响。接口类型定义格式为:接口修饰符interfac

e接口名:基接口列表{接口体}接口修饰符通常是public,interface是接口定义关键字,若没有基接口,则基接口可以省略。例如:publicinterfaceIexample{intthis[intindex]

{get;set;}//定义索引指示器eventEventHandlerChanged;//定义事件voidFind(intvalue);//定义方法stringP{get;set;}//定义属性}关于接口的说明:①接口可以定义零个或多个成员。接口的成员必

须是方法、属性、事件或索引器,且不包含方法的实现。接口不能包含常数、字段、运算符、构造函数、析构函数或类型,也不能包含任何种类的静态成员。②接口成员定义不能包含任何修饰符,接口成员被隐式声明为public。③接口允许多重继承,即可以

继承多个基接口,接口不能继承类。接口的成员由本身定义的成员和从基接口继承的成员组成。若接口定义的成员与基接口中继承而来的成员同名,在其定义前加上一个new关键字,表示覆盖了继承而来的同名成员。④派生类可以继承于一个基类和多个接口,基类必须是列

表中的第一项,用此方法可以解决类的多重继承问题。⑤若一个类继承于接口,则它必须提供接口的所有成员的具体实现,包括接口中显式定义的成员,以及接口从父接口中继承而来的成员。同时,该类的派生类可以对基类已经实现的接口进行重实现。⑥不能实例化一个接口,但接口可以引用派生对象。【案例】利用接

口实现工作人员工作经历的相关操作描述usingSystem;{...此部分的代码为11-12教材_事件案例中,自定义事件类和Person类的代码部分...}publicdelegatevoidEventHan

dler(objectsender,MyEventArgse);//定义修改姓名事件委托publicdelegatevoidWorkEventHandler(objectsender,EventArgse);//定义修改工作经历事件委托namespace教材_接口

{classProgram{staticvoidMain(string[]args){Personp1=newPerson("320401199011113456","王贝");//设置p1的Changed事件响应函数为PersonNameChangedp1.Changed+=

newEventHandler(PersonNameChanged);//改变p1的Name属性值,产生事件,调用事件处理函数p1.Name="理想";Workerp2=newWorker("320402199012126789","小裴","2000-至今,无锡

德实印刷厂");//设置p2的Changed事件响应函数为PersonNameChangedp2.Changed+=newEventHandler(PersonNameChanged);p2.Name=

"张飞";//产生修改姓名的事件//设置p2的WorkChanged事件响应函数为PersonWorkChangedp2.WorkChanged+=newWorkEventHandler(PersonWorkChanged);p2.WorkExperience="常州

戚机厂";//产生修改工作经历的事件Console.ReadKey();}//定义事件的处理函数staticvoidPersonNameChanged(objectsender,MyEventArgse){Console.Writ

eLine(e.OldName+"改名为"+e.NewName);}staticvoidPersonWorkChanged(objectsender,EventArgse){Console.WriteL

ine(((Worker)sender).Name+"修改了工作经历");//通过事件源对象获取其姓名}}}定义事件的处理函数:修改姓名事件处理函数、修改工作简历事件处理函数publicinterfaceIWorkExperience//定义接口{st

ringWorkExperience{get;set;}eventWorkEventHandlerWorkChanged;//定义事件}publicclassWorker:Person,IWorkExperience

{publiceventWorkEventHandlerWorkChanged;//重定义事件//为从接口处继承来的WorkExperience属性绑定私有字段privatestringworkexperience;publicstringWorkExperience{get

{returnworkexperience;}set{workexperience=value;OnWorkChanged(newEventArgs());//修改工作经历时,触发事件}}定义Worker类,在其中定义:修改工作简

历时,触发事件publicWorker(stringpid,stringpname,stringwe):base(pid,pname){workexperience=we;}publicvirtualvoidOnWo

rkChanged(EventArgse){if(WorkChanged!=null)WorkChanged(this,e);}}10.14运算符重载C#允许对自定义类型进行运算符重载。在C#中,可重载操作符分三种:一元操作符、二元操作符和类型转换操作符。不允许重载:赋

值运算符(=)、各种复合赋值运算符(+=、*=等)、三目运算符(?:)、逻辑与(&&)、逻辑或(||)、索引运算符([])、new、is、sizeof和typeof等都。类别运算符重载限制算术一元运算符+,–,++,––无算术二元运算符

+,*,/,–,%无按位一元运算符!,~,true,falsetrue和false运算符必须成对重载关系运算符==,!=,>=,<,<=,>==和!=,>=和<=,<,和>必须成对重载数据类型转换运算符()不能直接重载数据类型转换运算符,允许定义定制的数据类型转换可重载运算符运算符重载定义

一元运算符定义形式:publicstatic运算结果类型operator一元运算符(类型操作数参数名){…}二元运算符定义形式:publicstatic运算结果类型operator二元运算符(类型左操作数参数名,类型右操作数参数名){…}在重载运算符时,必须注意

以下几点:不能更改运算符的操作个数、优先级和结合性。不能更改运算符本生的功能。不能创造新的运算符符号。运算符重载函数的形参中,至少有一个参数属于自定义类型。【案例5】利用“==”运算符重载,实现两个引用类型变量的值相等运算。usingSystem;namespa

ce运算符重载{classProgram{staticvoidMain(string[]args){Aa1=newA(5);Aa2=newA(5);//使用==比较对象,是判断他们是否引用同一个对象,而不是判断他们的值是否相同if(a1==a2)

Console.WriteLine("a1==a2");elseConsole.WriteLine("a1!=a2");SubAb1=newSubA(10,20);SubAb2=newSubA(10,20);if(b1==b2)Console.WriteLine("b1

==b2");elseConsole.WriteLine("b1!=b2");Console.ReadKey();}}}classA{publicinta;publicA(intp_a){a=p_a;}

}classSubA:A{publicintj;publicSubA(intp_a,intp_j):base(p_a){j=p_j;}publicstaticbooloperator==(SubAp

_sub1,SubAp_sub2){if(p_sub1.a==p_sub2.a&&p_sub1.j==p_sub2.j)returntrue;returnfalse;}publicstaticbooloperator!=(SubAp_sub1,SubAp_sub2){if(p

_sub1.a!=p_sub2.a||p_sub1.j!=p_sub2.j)returntrue;returnfalse;}}【案例6】利用运算符重载实现复数的四则运算usingSystem;namespace教材_运算符

重载1{classProgram{staticvoidMain(string[]args){Complexnum1=newComplex(10,20);Complexnum2=newComplex(30,40);

Complexnum3=num1+num2;Complexnum4=num1-num2;Complexnum5=num1*num2;Complexnum6=num1/num2;Console.WriteLine("num1:{0}",num1);//输出时,调用num1.To

String()方法Console.WriteLine("num2:{0}",num2);Console.WriteLine("num3:{0}",num3);Console.WriteLine("num4:{0}",num4);Console

.WriteLine("num5:{0}",num5);Console.WriteLine("num6:{0}",num6);Console.ReadKey();}}}定义复数类:重载+、-、*、/运算符publicclassComplex{publicintrea

l;publicintimaginary;publicComplex(intp_real,intp_imaginary){real=p_real;imaginary=p_imaginary;}publicstaticComplexoperator+(Com

plexc1,Complexc2){returnnewComplex(c1.real+c2.real,c1.imaginary+c2.imaginary);}publicstaticComplexoperato

r-(Complexc1,Complexc2){returnnewComplex(c1.real-c2.real,c1.imaginary-c2.imaginary);}publicstaticComplexoperator*(Complexc1

,Complexc2){returnnewComplex(c1.real*c2.real-c1.imaginary*c2.imaginary,c1.real*c2.imaginary+c1.imaginary*c2.real);}publicstaticComplexoperator/

(Complexc1,Complexc2){returnnewComplex(-c1.real*c2.real+c1.imaginary*c2.imaginary,-c1.real*c2.imaginary+c1.imaginary*c2.real)

;}publicoverridestringToString()//覆盖从object处继承来的ToString方法,实现复数格式输出{return(String.Format("{0}+{1}i",rea

l,imaginary));}}10.15命名空间.NETFramework类库是按照树形结构进行组织的命名空间,每个命名空间都包含了可在程序中使用的类型和其他子命名空间,命名空间是类、接口、委托或组件的容器。.程序员如果需要使用.NETFra

mework类库中的类或其它项目中定义的类,首先需要在项目的“引用”节点中添加该类所在命名空间的引用(也可以添加自定义项目的引用),由于系统在创建C#项目时,已经引用了最常用的基类DLL(程序集),所以前面章节

介绍的案例都不需要手工添加System命名空间。命名空间的定义命名空间的定义usingSystem;namespace命名空间名{类定义;接口定义;委托定义;子命名空间定义;//嵌套方式定义第二层子命名空间}在同一个命名空间中,成员不能同名

;不同命名空间的成员可以同名。usingSystem;namespace命名空间名.子命名空间名{类定义;接口定义;委托定义;子命名空间定义;//嵌套方式定义第三层子命名空间}【案例7】命名空间的定义usingSyst

em;namespace命名空间1{publicclassA{publicvoidf1(){Console.WriteLine("命名空间定义演示f1");}}publicclassB{publicvo

idf2(){Console.WriteLine("命名空间定义演示f2");}}namespace命名空间2{publicclassC{publicvoidf3(){Console.WriteLine("命名空间嵌套演示");}}}}说明:需要在此项目的属性栏

中,将“输出类型”由“控制台应用程序”改为“类库”。命名空间的使用使用命名空间的主要目的是获取其中定义的类。如在程序中,需要使用.NETFramework框架中的类或其它项目中的类,首先需要在项目的“引用”节点中添加该类所在命

名空间的引用,具体步骤见11.8类的多态性一节的案例说明。【案例】命名空间的使用usingSystem;using命名空间1;//using命名空间1.命名空间2;namespace教材_命名空间使用{cl

assProgram{staticvoidMain(string[]args){Aa1=newA();a1.f1();Bb1=newB();b1.f2();命名空间1.命名空间2.Cc1=

new命名空间1.命名空间2.C();//Cc1=newC();c1.f3();Console.ReadKey();}}}课后作业结合XSGL学生选课管理系统,设计student、course、use

r、sc四个类,student提供修改姓名的事件处理,course提供修改教室和教师的事件处理,sc提供修改分数的事件处理。提供services类,用上述4个类作为参数,实现student、course、user、sc的增删改查。如:Servic

es:insertstudent(student)Services:deletestudent(stuent)Services:updatestudent(student)Services:querystudent(paramsstring[]fieldname)//根据多个字段查

询学生信息Services:queryview(paramsstring[]fieldname)//在数据库中设计综合查询视图,利用此类在前台查询

小橙橙
小橙橙
文档分享,欢迎浏览!
  • 文档 25747
  • 被下载 7
  • 被收藏 0
相关资源
广告代码123
若发现您的权益受到侵害,请立即联系客服,我们会尽快为您处理。侵权客服QQ:395972555 (支持时间:9:00-21:00) 公众号
Powered by 太赞文库
×
确认删除?