实验三类与类的封装_第1页
实验三类与类的封装_第2页
实验三类与类的封装_第3页
已阅读5页,还剩6页未读 继续免费阅读

付费下载

下载本文档

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

文档简介

1、实验三类与类的封装【实验目的与要求】理解面向对象程序设计的思想和基本概念使用构造函数和析构函数,给类写方法,给一个类增加届性理解静态方法和实例方法之间的异同掌握方法的重载掌握类索引器的编写方式掌握运算符的重载【实验内容与步骤】类是C舫言实现面向对象程序设计的基础,它是C锥寸装的基本单元,类把对象、届性和方法这些类成员封装在一起构成一个有机的整体,即数据机构。在C孙,类是程序的最核心部分,没有了类,就连简单的C晰序都不能编译。类是可以包含数据成员(常数和字段)、函数成员(方法、届性、事件、索引器、运算符、实例构造函数、静态构造函数和析构函数)以及嵌套类型的数据结构。类类型支持继承,继承是派生类可

2、用以扩展和专用化基类的机制。一、类的声明类的声明就是定义一个新类,其格式如下:届性类修饰符class标识符:基类(类体;类声明包含一组可选的届性(C#使程序员可以创造新的说明性信息种类,称为届性),后跟一组可选的类修饰符(new;public;protected;internal;private;abstract;sealed),然后是关键字class和一个命名该类的标识符,接着是一个可选的继承基类,最后是可根据需要后接一个分号的类体。二、类的成员类的成员包括由它的类成员声明引入的成员和从直接基类继承的成员。类的成员分为下列几种类别:常数,表示与类相关联的常数值。字段,类的变量。方法,实现可由

3、类执行的计算和操作。届性,定义与读取和写入这些特性相关的命名特性。事件,定义可由类生成的通知。索引器,允许以与索引数组相同的方式索引类的实例。运算符,定义可以应用于类的实例的表达式运算符。实例构造函数,实现初始化类的实例所需要的操作。析构函数,实现在永久性放弃类的实例之前要执行的操作。静态构造函数,实现初始化类自身所需要的操作。类型,表示类的局部类型。可以包含可执行代码的成员被总称为类的函数成员。类的函数成员是该类的方法、届性、事件、索引器、运算符、实例构造函数、析构函数和静态构造函数。类声明创建新的声明空间,而由类声明包含的最近的类成员声明将新成员引入到此声明空间中。下列规则适用于类成员声明

4、:实例构造函数、静态构造函数和析构函数必须具有与最近的封闭类相同的名称。所有其他成员必须具有与最近封闭类不同的名称。常数、字段、届性、事件或类型的名称必须不同于在同一个类中声明的所有其他成员的名称。方法的名称必须不同于在同一个类中声明的所有其他非方法的名称。此外,方法的签名必须不同于在同一个类中声明的所有其他方法的签名。实例构造函数的签名必须不同于在同一个类中声明的所有其他实例构造函数的签名。索引器的签名必须不同于在同一个类中声明的所有其他索引器的签名。运算符的签名必须不同于在同一个类中声明的所有其他运算符的签名。类的继承成员不是类的声明空间的组成部分。因此,允许派生类用与继承成员相同的名称或

5、签名来声明成员(这实质上隐藏了继承成员)。三、构造函数与析构函数在可以访问一个类的方法、届性或任何其它东西之前,第一条执行的语句是包含有相应类的构造函数。甚至你自己不写一个构造函数,也会有一个缺省的构造函数提供给你。classTestClass(publicTestClass():base()(/由编译器提供一个构造函数总是和它的类名相同,但是,它没有声明返回类型。总之,构造函数总是public的,你可以用它们来初始化变量。publicTestClass()(/在这给变量/初始化代码等等。如果类仅包含静态成员(能以类型调用,而不是以实例调用的成员),你可以创建一个private的构造函数。pr

6、ivateTestClass()(尽管存取修饰符在这一章的后面将要大篇幅地讨论,但是private意味着从类的外面不可能访问该构造函数。所以,它不能被调用,且没有对象可以自该类定义被实例化。并不仅限于无参数构造函数一一你可以传递初始参数来初始化成员。publicTestClass(stringstrName,intnAge)(.作为一个C/C+®序员,你可能习惯于给初始化写一个附加的方法,因为在构造函数中没有返回值。当然,尽管在C孙也没有返回值,但你可以引发一个自制的异常,以从构造函数获得返回值。但是,当你保留引用给宝贵的资源,应该想到写一个方法来解决:一个可以被显式地调用来释放这些

7、资源。问题是当你可以在析构函数(以类名的前面加""的方式命名)中做同样的事情时,为何还要写一个附加的方法.TestClass()(/活除你应该写一个附加方法的原因是垃圾收集器,它在变量超出范围后并不会立即被调用,而仅当间歇期间或内存条件满足时才被触发。当你锁住资源的时间长于你所计划的时间时,它就会发生。因此,提供一个显式的释放方式是一个好主意,它同样能从析构函数中调用。publicvoidRelease()(/释放所有宝贵的资源TestClass()(Release();调用析构函数中的释放方法并不是必要的一一总之,垃圾收集会留意释放对象。但没有忘记活除是一种良好的习惯。四

8、、类方法既然对象能正确地初始化和结束,所剩下来的就是往类中增加功能。在大多数情况下,功能的主要部分在方法中能得到实现。以往,对于每个程序来说,所有的工作都在Main()方法中实现。这对于功能简单的程序是合适的,因为仅仅用来学习一些概念。有个更好的方法来组织你的程序,那就是使用方法。方法是很有用的,因为方法可以让你在不同的单元中分开设计你的逻辑模块。方法的结构格式如下:届性修饰符返回值类型方法名(参数)(方法体return表达式4.1.1值传递参数我们在前面的例子中见过的一个参数就是值传递参数。你用一个值传递参数通过值传递一个变量给一个方法一一方法的变量被调用者传递进来的值的一个拷贝初始化。活单

9、4.1示范值传递参数的使用。活单4.1通过值传递参数1:usingSystem;2:3:publicclassSquareSample4:5:publicintCalcSquare(intnSideLength)6:7:returnnSideLength*nSideLength;8:9:10:11:classSquareApp12:13:publicstaticvoidMain()14:15:SquareSamplesq=newSquareSample();16:Console.WriteLine(sq.CalcSquare(25).ToString();17:18:因为传递值而不是引用(地址

10、)给一个变量,所以当调用方法时(见第16行),可以使用一个常量表达式(25)。4.1.2引用参数尽管可以利用值传递参数和返回值建立很多方法,但你一想到要传递值并原地修改它(也就是在相同的内存位置),就没有那么好操作了。这里用引用参数就很方便。voidmyMethod(refintnInOut)因为传递了一个变量给该方法(不仅仅是它的值),变量必须被初始化。否则,编译器会报警。活单4.2显示如何用一个引用参数建立一个方法。活单4.2通过引用传递参数1:/classSquareSample2:usingSystem;3:4:publicclassSquareSample5:6:publicvoid

11、CalcSquare(refintnOne4All)7:8:nOne4All*=nOne4All;9:10:11:12:classSquareApp13:14:publicstaticvoidMain()15:16:SquareSamplesq=newSquareSample();17:18:intnSquaredRef=20;/一定要初始化19:sq.CalcSquare(refnSquaredRef);20:Console.WriteLine(nSquaredRef.ToString();21:22:正如所看到的,所有要做的就是给定义和调用都加上ref限定符。因为变量通过引用传递,就可以用

12、它来计算出结果并传回该结果。但是,在现实的应用程序中,强烈建议要用两个变量,一个值传递参数和一个引用参数。4.1.3输出参数传递参数的第三种选择就是把它设作一个输出参数。正如该名字所暗示,一个输出参数仅用于从方法传递回一个结果。它和引用参数的另一个区别在于:调用者不必先初始化变量才调用方法。这显示在活单4.3中。1:usingSystem;2:3:publicclassSquareSample4:5:publicvoidCalcSquare(intnSideLength,outintnSquared)6:7:nSquared=nSideLength*nSideLength;8:9:10:11:

13、classSquareApp12:13:publicstaticvoidMain()14:15:SquareSamplesq=newSquareSample();16:17:intnSquared;/不必初始化18:sq.CalcSquare(15,outnSquared);19:Console.WriteLine(nSquared.ToString();20:21:4.1.4数组参数的传递当方法的参数前带有params关键字,这就是一个带数组型参数的方法在方法的参数列表中使用params关键字,可用于表示方法的形参个数不确定,这样就可以在使用方法的过程中改变传入方法的实参个数.带有关键字pa

14、rams的数组型参数必须是方法的参数歹U表中最后一个参数,否则会出现编译错误.数组型参数中的数组必须是一维数组类型,如int,string(锯齿型数组),但int,二维数组则不能用来作为数组参数.示例3:usingSystem;publicclassParamTestpublicvoidpara(paramsintary)/定义带数组型参数的方法成员Console.Write("n数组中包含0个元素:",ary.Length);for(intt=0;t<ary.Length;t+)aryt+;/改变形参数组元素的值Console.Write("t0,aryt

15、);/打印形参数组元素的值publicstaticvoidMain()(intm=1,n=2,p=3,q=4;ParamTestapp=newParamTest();inttestArr=newintm,n,5;Console.WriteLine("调用方法之前的数组元素值为:");foreach(inttintestArr)Console.Write(t0,t);/打印形参数组元素的值app.para(testArr);/用数组名作为实参Console.WriteLine("n调用方法之后的数组元素值为:”);foreach(inttintestArr)Cons

16、ole.Write("t0”,t);/打印形参数组元素的值app.para(m,n,p,q);/有4个实参与形参类型对应Console.WriteLine();五、静态方法与实例方法在类中,与上述实例方法相对应的是静态方法,在定义类的方法成员时带上Static修饰符,就可以将方法定义为静态方法。另外注意,定义一个静态方法时,不能含有Virtual,abstract,和override修饰符。静态方法与静态成员变量类似,虽然在类中定义它,但他不届于某个具体的实例。静态方法只能访问类中的静态成员,而实例方法可以访问类中的所有成员。示例1:publicclassstudentstatici

17、ntstudcount=0;/定义一个私有的静态变量成员,用于统计学生人数publicstudent()(studcount+;/统计学生人数publicstaticintGetStudentCount()/定义一个静态方法(return(studcount);/静态方法访问静态成员变量classAppStud(publicstaticvoidMain()(studentstudent1=newstudent();/创建类的一个实例Console.WriteLine("学生人数=0”,student.GetStudentCount();/通过类名访问静态方法studentstuden

18、t2=newstudent();/创建类的另一个实例Console.WriteLine("学生人数=0”,student.GetStudentCount();六、方法重载重载是面向对象程序设计的一个重要特征,通过重载可以使多个具有相同功能但参数不同的方法共享同一个方法名.这样将降低程序员的工作强度.示例2:UsingSystem;Classprintclasspublicvoidprint(inti)/打印整数Console.WriteLine(“打印整数0,i);publicvoidprint(uinti)/打印整数(Console.WriteLine(“打印整数0,i);打印字符

19、申“打印字符申0”,s);Publicvoidprint(strings)/Console.WriteLine(Publicvoidprint(paramsintarys)/打印数组foreach(intainarys)Console.Write(“0t,a);PublicstaticvoidMain()intmyary=newint2,4,6,8,10;Printclassapp=newprintclass();App.print(int)6);/调用打印整数方法App.print(uint)6);/调用打印无符号整数方法App.print(“方法重载好处多!”);/调用打印字符申方法App

20、.print(myary);/调用打印数组方法七、类届性届性是提供对对象或类的特性的访问的成员。届性的示例包括字符申的长度、字体的大小、窗口的标题、客户的名称,等等。届性是字段的自然扩展两者都是具有关联类型的命名成员,而且访问字段和届性的语法是相同的。然而,与字段不同,届性不表示存储位置。相反,届性有访问器,这些访问器指定要在它们的值被读取或写入时执行的语句。因此届性提供将操作与对象届性的读取和写入相关联的机制;另外,它们还允许对此类届性进行计算。届性声明:class类名(修饰符数据类型届性名(get;set;示例4:本示例展示一个Person类,它有两个届性:Name(string)和Age

21、(int)。两个届性都是读/写届性。/person.csusingSystem;classPersonprivatestringmyName="N/A"privateintmyAge=0;/DeclareaNamepropertyoftypestring:publicstringNamegetreturnmyName;setmyName=value;/DeclareanAgepropertyoftypeint:publicintAgegetreturnmyAge;set(myAge=value;publicoverridestringToString()(return&qu

22、ot;Name="+Name+",Age="+Age;publicstaticvoidMain()(Console.WriteLine("SimpleProperties");/CreateanewPersonobject:Personperson=newPerson();/Printoutthenameandtheageassociatedwiththeperson:Console.WriteLine("Persondetails-0”,person);/Setsomevaluesonthepersonobject:person.N

23、ame="Joe"person.Age=99;Console.WriteLine("Persondetails-0",person);/IncrementtheAgeproperty:person.Age+=1;Console.WriteLine("Persondetails-0",person);输出SimplePropertiesPersondetails-Name=N/A,Age=0Persondetails-Name=Joe,Age=99Persondetails-Name=Joe,Age=100代码讨论请注意声明届性的方式,

24、例如,考虑Name届性:publicstringNameget(returnmyName;set(myName=value;届性的“设置”(Set)方法和“获取”(Get)方法包含在届性声明中。可以通过控制是否包含“获取”方法或“设置”方法来控制届性是读/写届性、只读届性还是只写届性。声明了届性后,可像使用类的字段那样使用这些届性。这使得获取和设置届性值时都可以使用非常自然的语法,如以下语句中所示:person.Name="Joe"person.Age=99;注意届性“设置”方法中可以使用一个特殊的value变量。该变量包含用户指定的值,例如:myName=value;请注

25、意用于使Person对象上的Age届性递增的简洁语法:person.Age+=1;如果使用单独的“设置”方法和“获取”方法建立届性模型,等效代码可能是:person.SetAge(person.GetAge()+1);本示例中重写了ToString方法:publicoverridestringToString()(return"Name="+Name+",Age="+Age;注意程序中未显式使用ToString。默认情况下,它由WriteLine调用来调用。八、类索引索引器是使对象能够用与数组相同的方式进行索引的成员。索引器的工作方式类似于届性。只是索引

26、器用来访问类中的数组型对象元素,而届性用来被用来访问类中的私有变量成员,所以定义索引器时,也要使用get和set访问函数,不同的是使用索引器取得的是类实例中数组对象的各元素的值,而不是特定的数据成员。定义届性时需要定义届性的名称,而定义索引器时不需要给出具体的名称,只需要使用关键字this,它用于引用当前的对象实例。索引器的声明:修饰符数据类型thisintindex(get访问器索引器的get访问器体与方法体类似。它返回索引器的类型。get访问器使用与索引器相同的formal-index-parameter-list。例如:get(returnScoreArrayindex;set访问器索引

27、器的set访问器体与方法体类似。除了value隐式参数外,它还使用与索引器相同的formal-index-parameter-list。例如:set(ScoreArrayindex=value;示例5:此示例声明私有数组字段ScoreArray和一个索引器。通过使用索引器可直接访问实例bi。另一种使用索引器的方法是将数组声明为public成员并直接访问它的成员ScoreArrayi。usingSystem;classIndexerClass(privateintScoreArray=newint10;publicintthisintindex/索引器的声明(get(/检查索引器的范围if(in

28、dex<0|index>=10)return0;elsereturnScoreArrayindex;set(if(!(index<0|index>=10)ScoreArrayindex=value;publicclassMainClass(publicstaticvoidMain()(IndexerClassb=newIndexerClass();/调用索引器初始化数组中的第4个和第6个元素b3=256;b5=1024;for(inti=0;i<=11;i+)(Console.WriteLine("数组元素#0=1”,i,bi);程序运行结果如下:ciV

29、isualstudio,NET命令提示,MyCs>&avingftccountwverl储户的月利息6.666667,余额为:2跚6.667I愈“2储户的月利息为12.5,余额为:3012-5ILwlyCs>cscindexclass.cclicrosoft<B>UisualCtt.NETCompileruer-sion7_00_946&orMicrosoftR-NETFramekporkversion1.0.3705汲权所有<C>MicrosoftCorporation28814保留所有权利。兀一兀一兀元元兀元兀元兀一岫#1?it01鄙网t

30、tlltl62s02010:xMyCs>九、运算符重载所有一元和二元运算符都具有可自动用丁任何表达式的预定义实现。除了预定义实现外,还可通过在类或结构中包括operator声明来引入用户定义的实现。用户定义的运算符实现的优先级总是高丁预定义运算符实现:仅当没有适用的用户定义运算符实现时才会考虑预定义运算符实现。“可重载的一元运算符”有:+-I+_truefalse“可重载的二元运算符”有:+-*/%&|A<<>>=!=><>=<=只有以上所列的运算符可以重载。具体说来,不可能重载成员访问、方法调用或=、&&|、?:、checked、unchecked、newtypeof、as和is运算符。当重载二元运算符时,也会隐式重载相应的赋值运算符(若有)。例如,运算符*的重载也是运算符*=的重载。请注意,赋值运算符本身(=)无

温馨提示

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

评论

0/150

提交评论