第章面向对象编程技术.docx

上传人:scccc 文档编号:13808045 上传时间:2022-01-24 格式:DOCX 页数:25 大小:71.35KB
返回 下载 相关 举报
第章面向对象编程技术.docx_第1页
第1页 / 共25页
第章面向对象编程技术.docx_第2页
第2页 / 共25页
第章面向对象编程技术.docx_第3页
第3页 / 共25页
第章面向对象编程技术.docx_第4页
第4页 / 共25页
亲,该文档总共25页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《第章面向对象编程技术.docx》由会员分享,可在线阅读,更多相关《第章面向对象编程技术.docx(25页珍藏版)》请在三一文库上搜索。

1、第4章 面向对象编程技术面向对象的程序设计方法是当前程序设计的大势所趋。面向对象的程序设计方法是对结构化程序设计方法的重新认识。在程序的设计中,方法总是与特定的数据结构密切相关的,方法含有对数据结构的访问,特定的方法只适用于特定的数据结构,因此方法与数据结构在编程中应该是一个密不可分的整体,这个整体叫对象。C#通过类、对象、继承、多态等机制形成一个完善的面向对象的编程体系。4.1类和对象类是 C#程序设计的基本单位。类和对象概述现实生活中的类是人们对客观对象不断认识而产生的抽象的概念,而对象则是现实生活中的一个个实体。例如,人们在现实生活中接触了大量的汽车、摩托车、自行车等实体,从而产生了交通

2、工具的概念,交通工具就是一个类,而现实生活中的具体的汽车、摩托车自行车等则是该类的对象。面向对象程序设计的类从本质上和人们现实生活中的这一认识过程是相同的。例如在编程实践中,人们经常使用按钮这一控件,每一个具体的按钮是一个按钮对象,而按钮类则是按钮对象的抽象,并且人们把这一抽象用计算机编程语言表示为数据集合与方法集合的统一体,然后再用这个类创建一个个具体的按钮对象。可以把类比作一种蓝图,而对象则是根据蓝图所创建的实例,可以把类比作生产模具,而对象则是由这种模具产生的实例(产品)。所以人们又把对象叫做类的实例。类是对事物的定义,而对象则是该事物本身。在 Visual Studio.NET 集成环

3、境中的,工具箱中的一个个控件,是被图形文字化的可视的类,而把这些控件添加到窗体设计器中后,窗体设计器中的控件则是对象,即由工具箱中的类创建的对象。类是一种数据类型,在C# 中,类这种数据类型可以分为两种:一种是由系统提供的预先定义的,这些类在 .NET 框架类库中;一种是用户定义数据类型。在创建对象之前必须先定义该对象所属的类。然后由类声明对象。类本质上是一种数据类型,所以类的用法与基本数据类型的用法基本相同,事实上,在 Visual Studio.NET 中像 int 、 float 等基本数据类型也是特殊的类。那么,用基本数据类型可以声明变量,用类类型也可以声明变量,只不过类类型的变量叫类

4、的对象或类的实例。1/25类定义类定义的格式与结构定义的格式相似,在类定义中需要使用关键字class,其简单的定义格式为:class 类名 类体 “类名”是一个合法的 C#标识符,表示数据类型(类类型)名称,“类体”以一对大括号开始和结束,在一对大括号后面可以跟一个分号。例如:class student/ 类名为 studentpublic string ID 。public string Name 。public bool Sex 。上 例 中 , 定 义 了 一 个 名 为 “ student ” ( 学 生 ) 的 类 , 类 体 中 包 括 学 生 的 学 号(“ ID ”)、姓名(“

5、 Name ”)与性别(“ Sex”)。在上例的“类体”中声明的数据都使用“ public ”修饰,“ public ”(公共的)表示这些数据可以直接进行访问。如果仅从“ student”类的定义形式看,其与结构类型除了关键字外几乎没有任何差别。当然这只是为了说明问题方便,这种定义方式并不符合面向对象程序设计的原则,因为类中缺少了对数据的操作。“类体”包括类中的所有数据及对数据的操作,面向对象程序设计将数据与对数据的操作作为一个整体,以类的形式进行定义,这种机制叫“封装”。在“类体”中,所有的数据及对数据的操作的集合叫类成员,类成员的种类很多,本章仅介绍“字段”、“属性”、“方法”与“构造函数

6、”。“字段”是类定义中的数据,也叫类的变量。在上例中定义的“ID ”、“ Name”与“ Sex”等均为类中的字段。“属性”用于读取和写入“字段”值,“属性”是字段的自然扩展,对用户而言,“属性”等同于“字段”本身,对程序员而言,属性是一种读写“字段”的特殊方法。“方法”实质上就是函数,用于对字段进行计算和操作,即对类中的数据进行操作,以实现特定的功能。声明与使用对象定义类之后,可以用定义的类声明对象,声明对象后可以访问对象成员。每一个类对象均具有该类定义中的所有成员,正如每一个整型变量均可以表示同样的数值范围一样。1. 声明对象声明对象的格式与声明基本数据类型的格式相同:类名 对象名。例如:

7、2/25student S1 。/ 声明一个学生类对象S1但是,对象声明后,需用“new”关键字进行初始化,这样才能为对象在内存中分配保存数据的空间。初始化的格式:对象名 =new 类名 ( ) 。例如:S1=new student( ) 。/ 为 S1 分配内存空间可以将声明与初始化对象合二为一,例如:student S1=new student( ) 。/ 声明对象并初始化2.访问对象访问对象实质是访问对象成员,对对象变量成员的访问与结构变量相同,使用“. ”运算符。例如:S1.ID=12345 。S1.Name= 张三 。S1.Sex=true。上面的代码为对象S1 数据成员赋值。可以使

8、用对象变量为另一对象变量整体赋值,例如,“student S2。 S2=S1。 ”或“ studentS2=S1。”。这时,不需要使用new关键字对“ S2”初始化。可以使用对象中的某一成员。例如:string sName=S1.Name 。/ 将对象 S1 的 Name 成员值赋给字符串变量sName值类型与引用类型类定义的类型与结构定义的类型虽然相似,但这两种类型却有很大的差别,这涉及到C#中变量存储方式的问题。从变量的存储方式看,C#中的变量可以分为值类型变量与引用类型变量。1. 值类型值类型变量直接包含其本身的数据,因此每个值类型变量本身就包含有赋给它的值。在 C#中,内置数据类型除了

9、字符串(string )类型与对象( object)类型外其余均为值类型。枚举类型与结构类型也是值类型。例如“int X =42 。”,整型变量X 就是值类型。2. 引用类型与值类型不同,引用类型变量不包含本身的数据,只是存储对数据的引用,数据保存在内存的其他位置。例如:using System 。class Class1class Testpublic int A 。static void Main(string args)3/25int X=42,Y=X 。Test T1=new Test() 。T1.A=42 。Test T2=T1 。Y=100 。T2.A=100 。引用类型与值类型在

10、内存中的存储形式如图4-1 所示。int X=42 。42T1.A=42 。42 的引用42图 4-1 值类型与引用类型的存储值类型变量可以使用变量来赋值,引用类型变量也可以使用变量来赋值。例如上例中的代码:int X=42,Y=X。Test T1=new Test() 。T1.A=42 。Test T2=T1 。/ 使用对象变量赋值但是,值类型与引用类型用变量赋值的性质却不同,如图4-2 所示。int X=42 。int Y=X。4242T1.A=42 。42 的引用42Test T2=T1 。42 的引用图 4-2 值类型与引用类型用变量赋值从图中可以看到,用变量“X ”为变量“ Y ”赋

11、值,是将“X ”所在内存中的值复制给了“ Y ”;而用变量“ T1”为“ T2”赋值,则是将“ T1”对数据的引用复制给了“T2 ”,即两个对象变量使用的是同一内存中的数据,也就是说,用“T1”为“ T2 ”赋值不需要使用new 关键字对对象初始化,也就没有为对象“T2”分配存储数据的内存空间。这样,在改变变量值时,将发生本质差别。例如上例中的代码:Y=100 。 /Y 的值为 100, X 的值仍是 42T2.A=100 。 / 不仅 T2的值为 100 ,T1的值也为 100访问控制在上面类定义的例子中,声明类的数据成员(字段)时,均使用public 进行修饰, public叫访问修饰符。

12、声明类中的成员时,使用不同的访问修饰符,表示对类成员的访问权限不同,或者说访问修饰符确定了在什么范围可以访问类成员。4/25C#中最常用的访问修饰符及其意义,如表4-1 所示。表 4-1访问修饰符访问修饰符意义public (公有)访问不受限制,可以被任何其他类访问private (私有)访问只限于含该成员的类,即只有该类的其他成员能访问protected (保护)访问只限于含该成员的类、及该类的派生类在类定义中,如果声明成员没有使用任何访问修饰符,则该成员被认为是私有(private )的。如果不涉及继承,private 与 protected 没有什么区别。在类定义中,如果成员被声明为pr

13、ivate 或 protected ,则不允许在类定义外使用点运算符访问,即在类定义外,点运算符只能访问public 成员。例如在下面的类定义中:class student/ 类名为 studentprivate string ID 。/ 私有public string Name 。/ 公有protected bool Sex 。/ 保护student S1=new student( ) 。S1.ID=12345 。/ 非法, ID 为 privateS1.Name= 张三 。/ 合法, Name 为 publicS1.Sex=true。/ 非法, Sex 为 protected在类定义外使用

14、点运算符访问“ID ”与“ Sex”是非法的,而访问“Name ”则是合法的,因为“ ID ”与“ Sex”是 private 或 protected 的,而“ Name ”则是 public 的。通常,在类定义中,数据成员(字段)被声明为private 或 protected ,从而实现所谓的数据隐藏,以确保不能在类外随意访问类的数据成员;而其他种类的成员则被声明为public ,以通过这些成员实现对类的数据成员的访问。4.2属性对私有或保护数据成员常见的访问是读取与设置修改数据值,在类定义外部,这种访问可通过属性成员实现。通过属性可以控制对数据的访问方式,甚至设置数据可接受的值域。声明属性

15、在类定义中声明属性的格式为:访问修饰符类型属性名 可以将属性声明为读写属性、只读属性或只写属性。1. 声明读写属性修改 student 类定义添加属性声明:class student/ 类名为 student/声明字段5/25private string id 。private string name 。private bool sex 。/声明属性public string IDgetreturn id 。setid=value 。public string Namegetreturn name 。setname=value 。public bool Sexgetreturn sex。set

16、sex=value 。在属性声明中, get 与 set 叫属性访问器。get 完成对数据值的读取, return 用于返回读取的值; set 完成对数据值的设置修改,value 是一个关键字,表示要写入数据成员的值。属性名应和其要访问的数据成员名相关但不相同,可以采取数据成员名全用小写,而属性名的单词首字母大写的方式,如数据成员名为name,则对应的属性名为 Name 。6/252. 声明只读或只写属性在属性声明中,如果只有get 访问器,则该属性为只读属性。例如:public bool Sexgetreturn sex。只读属性意味着,数据成员的值是不能被修改的。在属性声明中如果只有 se

17、t 访问器,则该属性为只写属性。只写属性在程序设计中不常使用。使用属性属性成员的使用就如同公有数据成员的使用一样。可以为可写的属性赋值,可以用可读的属性为其他变量赋值。以 student 类为例:student S1=new student( ) 。/ 用属性设置修改数据成员值S1.ID=12345 。S1.Name= 张三 。S1.Sex=true。/ 用属性读取数据成员值为其他变量赋值bool SSex=S1.Sex。如果属性为只读的,则属性不能出现在赋值运算符的左边。在 C#程序设计中,窗体与控件的属性就是这类成员,其中在属性窗口显示的属性,均为可读写属性,窗体与控件的只读属性只能在代码

18、中使用。4.3方法方法是把一些相关的语句组织在一起,用于解决某一特定问题的语句块。方法必须放在类定义中。方法同样遵循先声明后使用的规则。声明与调用方法方法的使用分声明与调用两个环节。1. 声明方法声明方法最常用的格式:访问修饰符返回类型方法名 ( 参数列表 ) 方法的访问修饰符通常是public ,以保证在类定义外部能够调用该方法。方法的返回类型用于指定由该方法计算和返回的值的类型,可以是任何值类型或引用类型数7/25据,如, int 、 string 及前面定义的student 类。如果方法不返回一个值,则它的返回类型为void 。方法名是一个合法的C#标识符。参数列表在一对圆括号中,指定调

19、用该方法时需要使用的参数个数、各个参数的类型,参数之间以逗号分隔。参数可以是任何类型的变量。如果方法在调用时不需要参数,则不用指定参数,但圆括号不能省。实现特定功能的语句块放在一对大括号中,叫方法体,“ ”表示方法体的开始,“ ”表示方法体的结束。如果方法有返回值,则方法体中必须包含一个return 语句,以指定返回值,该值可以是变量、常量、表达式,其类型必须和方法的返回类型相同。如果方法无返回值,在方法体中可以不包含return 语句,或包含一个不指定任何值的return 语句。例如下面的方法声明:public int IntMax(int a,int b)int c 。if(ab)c=a。

20、elsec=b。return c 。该方法的功能是求两个整数中较大的整数,并将该整数返回。该方法的返回类型是一个整型值,方法名称为“IntMax ”,参数列表中有两个整型变量参数“a”与“ b”,方法体中有一个return 语句,该语句指定的返回值是一个整型变量c。该方法体中的语句块也可以用条件表达式合并为一句:“ return ab?a:b。”。这时, return 指定的返回值是一个条件表达式, return 语句把该表达式运算的结果返回。2.调用方法从方法被调用的位置,可以分为在方法声明的类定义中调用该方法和在方法声明的类定义外部调用方法。在方法声明的类定义中调用该方法的格式为:方法名

21、(参数列表 )在方法声明的类定义中调用该方法,实际上是由类定义内部的其他方法成员调用该方法。例如在类定义内部调用求较大整数函数:class CLASSMAXpublic int GetMax(int a,int b)/其他方法成员return IntMax(a,b) 。/ 在类定义CLASSMAX内部调用方法IntMax8/25public int IntMax(int a,int b)/求较大整数函数return ab?a:b。在方法声明的类定义外部调用该方法实际上是通过类声明的对象调用该方法,其格式为:对象名 .方法名 (参数列表 )【例 4-1】创建一个控制台应用程序,并创建一个类,该类

22、仅包含求两个数中较大数的方法成员,在 Main 方法中调用该方法。using System 。class Class1class CLASSMAX/定义一个类public int IntMax(int a, int b)return ab?a:b 。static void Main(string args)int X=42,Y 。Y=100 。CLASSMAX classmax=new CLASSMAX() 。 / 声明一个对象 int C=classmax.IntMax(X,Y) 。 / 调用对象方法 Console.Write( 较大的值为: ) 。Console.WriteLine(C)

23、 。Console.ReadLine() 。程序运行的结果为:较大的值为:100参数传递在方法的声明与调用中,经常涉及方法参数,在方法声明中使用的参数叫形式参数(形参),在调用方法中使用的参数叫实际参数(实参)。在调用方法时,参数传递就是将实参传递给形参的过程。以【例 4-1】为例,声明方法时的形参如下:9/25public int IntMax(inta,int b)调用方法时的实参如下:classmax.IntMax( X,Y)这样就完成了形参与实参的结合,其传递关系如图4-3 所示。方法调用: classmax.IntMax(X, Y)方法声明: public int IntMax(in

24、ta,intb)图 4-3 形参与实参方法参数传递按性质可分为按值传递与按引用传递。1. 按值传递参数按值的方式传递是指当把实参传递给形参时,是把实参的值复制(拷贝)给形参,实参和形参使用的是两个不同内存中的值,所以这种参数传递方式的特点是形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全。按值传递如图4-4 所示。实参形参传递图 4-4 按值传递示意基本类型的参数在传递时默认为按值传递。2. 按引用传递方法只能返回一个值,但实际应用中常常需要方法能够修改或返回多个值,这时只靠 return 语句显然是无能为力的。如果需要方法返回多个值,使用按引用传递参数的方式可以实现这种效果。按

25、引用传递是指实参传递给形参时,不是将实参的值复制给形参,而是将实参的引用传递给形参,实参与形使用的是一个内存中的值。这种参数传递方式的特点是形参的值发生改变时,同时也改变实参的值。按引用传递分基本数据类型与类对象数据类型两种情况,其传递如图4-5 与图 4-6 所示。实参传实参传递递形参形参图4-5基本类型按引用传递示意图 4-6类对象按引用传递示意基本类型参数按引用传递时,形参实际上是实参的别名。基本类型参数按引用传递时,实参与形参前均须使用关键字ref。【例 4-2】编写一个控制台应用程序,在程序中添加一个交换两个整型变量值的方法。调用该方法将两个整型变量的值进行交换并输出交换前后的结果。

26、using System 。10/25namespace 数值交换class Class1public void Swap(ref int a,ref int b)/形参 a、 b 为引用类型 / 数值交换int c=a 。a=b。b=c 。static void Main(string args)int A=60,B=80 。Console.WriteLine(交换前 A 、 B 的值: 0 , 1,A,B)Class1 c=new Class1( ) 。c.Swap(ref A,ref B)。 / 以引用方式传递实参A 、 BConsole.WriteLine(交换后 A 、 B 的值:

27、0, 1,A,B)Console.ReadLine( ) 。程序运行结果:交换前 A、 B 的值: 60, 80交换后 A、 B 的值: 80, 60因为在 Swap 方法中,对引用形参 a、 b 的值的修改,就是对实参 A 、 B 的值的修改,所以方法 Swap 成功地完成了对 A 、 B 数据的交换功能,相当于返回了两个值,这在按值传递的方式下是无法实现的。类对象参数总是按引用传递的,所以类对象参数传递不需要使用ref 关键字。类对象参数的传递,实际上是将实参对数据的引用复制给了形参,所以形参与实参共同指向同一个内存区域。【例4-3】编写一个控制台应用程序,该程序工程名称为“类对象参数”,

28、程序中有两个类定义,一个是创建程序时系统自动创建的类class1,一个是用户自定义的student 类。在class1 类中声明一个方法,该方法以student 类对象为参数。在class1 类中的Main 方法中调用该方法。using System 。namespace 类对象参数class student/ 类名为student/声明字段private string id 。11/25private string nameprivate bool sex 。/声明属性public string IDgetsetpublic string Namegetsetpublic bool Sex。

29、return id 。id=value 。return name 。name=value 。getreturn sex。setsex=value。class Class1public void StudentF1(student ST1)/以对象 ST1 为形参 / 修改形参数据成员的值ST1.ID=56789 。 ST1.Name= 张三 。12/25ST1.Sex=true 。static void Main(string args)string SSex 。student S1 。/ 声明一个学生类对象S1S1=new student( ) 。/ 为 S1 分配内存空间S1.ID=123

30、45 。S1.Name= 李平 。S1.Sex=false 。if (S1.Sex=true)SSex= 男 。elseSSex= 女 。Console.WriteLine(学生学号 :+S1.ID+姓名 :+S1.Name+ 性别 :+SSex) 。/ 输出对象S1 的值Class1 c=new Class1( ) 。 / 声明对象 c 以调用方法 StudentF1 c.StudentF1(S1) 。 / 以对象 S1 为实参调用方法if (S1.Sex=true)SSex= 男 。elseSSex= 女 。Console.WriteLine(学生学号 :+S1.ID+姓名 :+S1.Na

31、me+ 性别 :+SSex) 。/ 输出对象S1 的值Console.ReadLine( ) 。程序运行结果:学生学号: 12345 姓名:李平性别:女学生学号: 56789 姓名:张三性别:男结果的第一行为调用方法前对象S1 的值,结果的第二行为调用方法后对象S1 的值。虽然在 Main 方法中并未对对象S1 进行修改,但由于调用方法StudentF1 时,将S1 传递给了ST1,而类对象参数是按引用传递的,所以在方法StudentF1 中对 ST1 的修改,就是对S1 的修改,因此,结果的第二行,S1 的值发生了变化。重载方法有时候方法实现的功能需要针对多种类型的数据,虽然C#有隐式转换功

32、能,但这种转换在有些情况下会导致运算结果的错误,而有时数据类型无法实现隐式转换甚至根本无法转换。例如:using System 。class Class113/25public void Swap(ref int a,ref int b)int c=a 。a=b。b=c。static void Main(string args)int A=60,B=80 。Console.WriteLine(交换前 A 、 B 的值: 0 , 1,A,B)。Class1 c=new Class1( ) 。c.Swap(ref A,ref B)。 / 调用交换值方法Console.WriteLine(交换后 A

33、 、 B 的值: 0 , 1,A,B)。Console.ReadLine( ) 。上例中的交换方法只能实现两个整型变量的值交换,无法通过隐式或显式转换来实现其他类型变量的值交换。例如在上例的主方法中添加如下代码:float fA=5.2f,fB=6.0f。c.Swap(ref fA,ref fB)。运行程序时,将出现“无法从ref float 转换为 ref int ”的编译错误。为了能使同一功能适用于各种类型的数据, C#提供了方法重载机制。方法重载是声明两个以上的同名方法,实现对不同数据类型的相同处理。方法重载有两点要求:(1) 重载的方法名称必须相同;(2) 重载的方法,其形参个数或类型

34、必须不同,否则将出现“已经定义了一个具有相同类型参数的方法成员”的编译错误。如果要使上例中的交换方法能同时处理整型与浮点型数据,重载的方法声明如下:public void Swap(ref int a,ref int b)public void Swap(ref float a,ref float b)声明了重载方法后,当调用具有重载的方法时,系统会根据参数的类型或个数寻求最匹配的方法予以调用。根据前述的例子,当执行“c.Swap(ref A,ref B) 。”调用时,系统会调用“ public voidSwap(refint a,ref int b)”方法,当执行“c.Swap(ref fA

35、,ref fB) 。”调用时,系统会调用“publicvoid Swap(ref float a,ref float b)”方法,从而实现对不同的数据类型进行相同处理。【例 4-4 】创建一个控制台应用程序,在该程序中实现对两个整型、浮点型、双精度型、十进制型与字符型数据比较大小的功能。using System 。namespace 方法重载 _比较值的大小14/25class Class1/比较值大小的方法声明public int Max(int a, int b)return ab?a:b 。public float Max(float a, float b)return ab?a:b 。

36、public double Max(double a, double b)return ab?a:b 。public decimal Max(decimal a, decimal b)return ab?a:b 。public char Max(char a, char b)return ab?a:b 。static void Main(string args)int iA=60,iB=80。float fA=5.2f,fB=8.8f。double dA=6.2,dB=7.2 。decimal mA=8.2m,mB=9.8m。char cA=a,cB=b 。Class1 c=new Class

37、1( ) 。Console.WriteLine(iA与 iB 较大的值为:0,c.Max(iA,iB)。Console.WriteLine(fA与 fB 较大的值为:0,c.Max(fA,fB)。Console.WriteLine(dA与 dB 较大的值为:0,c.Max(dA,dB)。Console.WriteLine(mA与 mB 较大的值为:0,c.Max(mA,mB)。Console.WriteLine(cA与 cB 较大的值为:0,c.Max(cA,cB)。Console.ReadLine( ) 。程序运行结果为:iA 与 iB 较大的值为:8015/25fA 与 fB 较大的值为:

38、8.8dA 与 dB 较大的值为:7.2mA 与 mB 较大的值为:9.8cA 与 cB 较大的值为:b在上面的程序例题中,由于float 类型可以隐式转换为double 类型,因此比较float 类型的值大小的方法可以省略。int 类型可以实现隐式转换,但由于int 类型既可以隐式转换为double 类型,也可以隐式转换为decimal 类型,所以,比较int 类型值大小的方法不能省略,以免产生调用的二义性。4.4构造函数构造函数是一种特殊的方法成员,构造函数的主要作用是在创建对象(声明对象)时初始化对象。一个类定义必须有至少一个构造函数,如果定义类时,没有声明构造函数,系统会提供一个默认的构造函数,如果声明了构造函数,系统将不再提供构默认造函数。如果只有默认构造函数,在创建对象时,系统将不同类型的数据成员初始化为相应的默认值,如,数值类型被初始化为0,字符类型被初始化为空格,字符串类型被初始化为null(空值),逻辑(bool )类型被初始化为false 等。例如下面的程序:using System 。class student/ 类名为 student/声明字段public s

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

当前位置:首页 > 社会民生


经营许可证编号:宁ICP备18001539号-1