版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、第4章 面向对象编程技术面向对象的程序设计方法是当前程序设计的大势所趋。面向对象的程序设计方法是对结 构化程序设计方法的重新认识。在程序的设计中,方法总是与特定的数据结构密切相关的, 方法含有对数据结构的访问,特定的方法只适用于特定的数据结构,因此方法与数据结构在 编程中应该是一个密不可分的整体,这个整体叫对象。C#通过类、对象、继承、多态等机制形成一个完善的面向对象的编程体系。4.1 类和对象类是C#程序设计的基本单位。4.1.1 类和对象概述现实生活中的类是人们对客观对象不断认识而产生的抽象的概念,而对象则是现实生活 中的一个个实体。例如,人们在现实生活中接触了大量的汽车、摩托车、自行车等
2、实体,从 而产生了交通工具的概念,交通工具就是一个类,而现实生活中的具体的汽车、摩托车自行 车等则是该类的对象。面向对象程序设计的类从本质上和人们现实生活中的这一认识过程是相同的。例如在编 程实践中,人们经常使用按钮这一控件,每一个具体的按钮是一个按钮对象,而按钮类则是 按钮对象的抽象,并且人们把这一抽象用计算机编程语言表示为数据集合与方法集合的统一 体,然后再用这个类创建一个个具体的按钮对象。可以把类比作一种蓝图,而对象则是根据蓝图所创建的实例,可以把类比作生产模具, 而对象则是由这种模具产生的实例(产品)。所以人们又把对象叫做类的实例。类是对事物 的定义,而对象则是该事物本身。在 Visu
3、al Studio.NET 集成环境中的,工具箱中的一个个控件,是被图形文字化的可视的 类,而把这些控件添加到窗体设计器中后,窗体设计器中的控件则是对象,即由工具箱中的 类创建的对象。类是一种数据类型,在 C#中,类这种数据类型可以分为两种:一种是由系统提供的预先 定义的,这些类在 .NET 框架类库中;一种是用户定义数据类型。在创建对象之前必须先定 义该对象所属的类。然后由类声明对象。类本质上是一种数据类型,所以类的用法与基本数据类型的用法基本相同,事实上,在Visual Studio.NET 中像 int、 float 等基本数据类型也是特殊的类。那么,用基本数据类型可 以声明变量,用类类
4、型也可以声明变量,只不过类类型的变量叫类的对象或类的实例。4.1.2 类定义类定义的格式与结构定义的格式相似,在类定义中需要使用关键字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”等均为类中的字段。“属性”用于读取和写入“字段”值,“属性”是字段的自然扩展,对用户而言,“属性” 等同于“字段”本身,对程序员而言,属性是一种读写“字段”的特殊方法。“方法”实质上就是函数,用于对字段进行计算和操作,即对类中的数据进行操作,以实现 特定的功能。4.1.3 声明与使用对象定义类之后,可以用定义的类声明对象,声明对象后可以访问对象成员。每一个类对象 均具有该类定义中的所有成员,正如每一个整型变量均可以表示同样的数值范围一样。1. 声明对象 声明对象的格式与声明基本数据类型的
7、格式相同: 类名 对象名。例如:student S1 。 /声明一个学生类对象 S1但是,对象声明后,需用“ new”关键字进行初始化,这样才能为对象在内存中分配保存 数据的空间。初始化的格式:对象名 =new 类名 ( ) 。例如:S1=new student( ) 。 / 为 S1 分配内存空间 可以将声明与初始化对象合二为一,例如:student S1=new student( ) 。 / 声明对象并初始化2. 访问对象 访问对象实质是访问对象成员,对对象变量成员的访问与结构变量相同,使用“. ”运算符。例如:S1.ID=12345 。S1.Name=张三。 S1.Sex=true。上面
8、的代码为对象 S1 数据成员赋值。 可以使用对象变量为另一对象变量整体赋值,例如,“ student S2 。 S2=S1。 ”或“ studentS2=S1。”。这时,不需要使用 new关键字对“ S2”初始化。 可以使用对象中的某一成员。例如:string sName=S1.Name 。/ 将对象 S1 的 Name 成员值赋给字符串变量 sName4.1.4 值类型与引用类型类定义的类型与结构定义的类型虽然相似,但这两种类型却有很大的差别,这涉及到C#中变量存储方式的问题。从变量的存储方式看,C#中的变量可以分为值类型变量与引用类型变量。1. 值类型 值类型变量直接包含其本身的数据,因此
9、每个值类型变量本身就包含有赋给它的值。在C#中,内置数据类型除了字符串( string)类型与对象(object)类型外其余均为值类 型。枚举类型与结构类型也是值类型。例如“ int X =42。” ,整型变量 X 就是值类型。2. 引用类型 与值类型不同,引用类型变量不包含本身的数据,只是存储对数据的引用,数据保存在内存的其他位置。例如:using System 。class Class1class Testpublic int A 。static void Main(string args)int X=42,Y=X 。Test T1=new Test() 。T1.A=42。Test T2=
10、T1。Y=100。T2.A=100。引用类型与值类型在内存中的存储形式如图4-1所示。int X=42。42|T1.A=42。| 42的引用JJ 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。142| |42T1.A=42。| 42的引用一|42Test T2=T1。142的引用“图4-2值类型与引用类型用变量
11、赋值从图中可以看到,用变量“X”为变量“ Y”赋值,是将“ X”所在内存中的值复制给了“ Y ”;而用变量“ T1 ”为“ T2”赋值,则是将“T1 ”对数据的引用复制给了“T2 ”,即两个对象变量使用的是同一内存中的数据,也就是说,用“T1 ”为“ T2 ”赋值不需要使用new关键字对对象初始化,也就没有为对象“T2 ”分配存储数据的内存空间。这样,在改变变量值时,将发生本质差别。例如上例中的代码:Y=100。/Y的值为100,X的值仍是 42T2.A=100。/不仅T2的值为100,T1的值也为1004.1.5访问控制在上面类定义的例子中,声明类的数据成员(字段)时,均使用public进行
12、修饰,public叫访问修饰符。声明类中的成员时,使用不同的访问修饰符,表示对类成员的访问权限不 同,或者说访问修饰符确定了在什么范围可以访问类成员。C#中最常用的访问修饰符及其意义,如表4-1所示。表4-1访问修饰符访问修饰符意义public (公有)访问不受限制,可以被任何其他类访问private (私有)访问只限于含该成员的类,即只有该类的其他成员能访问protected (保护)访问只限于含该成员的类、及该类的派生类在类定义中,如果声明成员没有使用任何访问修饰符,则该成员被认为是私有(private)的。如果不涉及继承,private与protected没有什么区别。在类定义中,如果成
13、员被声明为private或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 属性对私有或保护数据成员常见的访问是读取与设置修改数据值,在类定义外部,这种访问 可通过属性成员实现。通过属性可以控制对数据的访问方式,甚至设置数据可接受的值域。4.2.1声明属性在类定义中声明
15、属性的格式为:访问修饰符类型属性名 可以将属性声明为读写属性、只读属性或只写属性。1.声明读写属性修改student类定义添加属性声明:class student / 类名为 student声明字段private string id 。private string name。private bool sex 。/声明属性public string IDgetreturn id 。setid=value 。public string Namegetreturn name 。setname=value 。public bool Sexgetreturn sex 。setsex=value 。在属性
16、声明中, get 与 set 叫属性访问器。 get 完成对数据值的读取, return 用于返回读取 的值; set 完成对数据值的设置修改, value 是一个关键字,表示要写入数据成员的值。属性名应和其要访问的数据成员名相关但不相同,可以采取数据成员名全用小写,而属性名的单词首字母大写的方式,如数据成员名为n ame,则对应的属性名为 Name。2. 声明只读或只写属性在属性声明中,如果只有 get 访问器,则该属性为只读属性。例如:public bool Sexgetreturn sex 。只读属性意味着,数据成员的值是不能被修改的。在属性声明中如果只有 set 访问器,则该属性为只写
17、属性。只写属性在程序设计中不常使 用。4.2.1 使用属性属性成员的使用就如同公有数据成员的使用一样。可以为可写的属性赋值,可以用可读 的属性为其他变量赋值。以 student 类为例: student S1=new student( ) 。 /用属性设置修改数据成员值 S1.ID=12345 。S1.Name=张三。S1.Sex=true。/用属性读取数据成员值为其他变量赋值bool SSex=S1.Sex 。如果属性为只读的,则属性不能出现在赋值运算符的左边。在C#程序设计中,窗体与控件的属性就是这类成员,其中在属性窗口显示的属性,均为 可读写属性,窗体与控件的只读属性只能在代码中使用。4
18、.3 方法方法是把一些相关的语句组织在一起,用于解决某一特定问题的语句块。方法必须放在 类定义中。方法同样遵循先声明后使用的规则。4.3.1 声明与调用方法方法的使用分声明与调用两个环节。1. 声明方法声明方法最常用的格式: 访问修饰符 返回类型 方法名 (参数列表 ) 方法的访问修饰符通常是 public ,以保证在类定义外部能够调用该方法。 方法的返回类型用于指定由该方法计算和返回的值的类型,可以是任何值类型或引用类型数 据,如, int 、string 及前面定义的 student 类。如果方法不返回一个值,则它的返回类型为 void 。方法名是一个合法的C#标识符。参数列表在一对圆括号
19、中,指定调用该方法时需要使用的参数个数、各个参数的类型, 参数之间以逗号分隔。参数可以是任何类型的变量。如果方法在调用时不需要参数,则不用 指定参数,但圆括号不能省。实现特定功能的语句块放在一对大括号中,叫方法体,“”表示方法体的开始,“ 表示方法体的结束。如果方法有返回值,则方法体中必须包含一个 return 语句,以指定返回值,该值可以是变 量、常量、表达式,其类型必须和方法的返回类型相同。如果方法无返回值,在方法体中可 以不包含 return 语句,或包含一个不指定任何值的 return 语句。例如下面的方法声明:public int IntMax(int a,int b)int c 。
20、if(ab)c=a。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 内部调用方法 IntMaxpublic int IntMax(int a,int b) / 求较大整数函数return ab?a:b 。在方法声明的类定义外部调用该方法实际上是通过类声明的对象调用该方法,其格式 为:对象名 .方法名 (参数列表 )【例 4-
22、1】创建一个控制台应用程序,并创建一个类,该类仅包含求两个数中较大数的方法 成员,在 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( 较大的值为:
23、 ) 。Console.WriteLine(C) 。Console.ReadLine() 。程序运行的结果为:较大的值为: 1004.3.2 参数传递在方法的声明与调用中,经常涉及方法参数,在方法声明中使用的参数叫形式参数(形 参),在调用方法中使用的参数叫实际参数(实参)。在调用方法时,参数传递就是将实参 传递给形参的过程。以【例 4-1 】为例,声明方法时的形参如下:public int IntMax(int a,int b)调用方法时的实参如下:classmax.IntMax( X,Y)这样就完成了形参与实参的结合,其传递关系如图4-3所示。方法调用:classmax.lntMax(X,
24、 Y)方法声明:public int IntMax(int a, int b)图4-3形参与实参方法参数传递按性质可分为按值传递与按引用传递。1.按值传递参数按值的方式传递是指当把实参传递给形参时,是把实参的值复制(拷贝)给形参, 实参和形参使用的是两个不同内存中的值,所以这种参数传递方式的特点是形参的值发生改 变时,不会影响实参的值,从而保证了实参数据的安全。按值传递如图4-4所示。实参传递形参图4-4按值传递示意基本类型的参数在传递时默认为按值传递。2.按引用传递方法只能返回一个值,但实际应用中常常需要方法能够修改或返回多个值,这时只靠 return语句显然是无能为力的。如果需要方法返回多
25、个值,使用按引用传递参数的方式可以 实现这种效果。4-5与图4-6所示。按引用传递是指实参传递给形参时,不是将实参的值复制给形参,而是将实参的引用传 递给形参,实参与形使用的是一个内存中的值。这种参数传递方式的特点是形参的值发生改 变时,同时也改变实参的值。图4-6类对象按引用传递示意按引用传递分基本数据类型与类对象数据类型两种情况,其传递如图传实参递 ,形参图4-5基本类型按引用传递示意基本类型参数按引用传递时,形参实际上是实参的别名。基本类型参数按引用传递时, 实参与形参前均须使用关键字ref。【例4-2】编写一个控制台应用程序,在程序中添加一个交换两个整型变量值的方法。调用 该方法将两个
26、整型变量的值进行交换并输出交换前后的结果。using Sspace数值交换class Class1 public 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.Write
27、Line( 交换后 A、 B 的值: 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、个控制台应用程序,该程序工程名称为“类对象参数”,程序中有两个类定义,一个是创建程序时系统自动创建的类classl,一个是用户自定义的 student类。在class1 类中声明一个方法,该方法以 student 类对象为参数。在 class1 类中的 Main 方法中调 用该方法。using System 。namespace 类对象参数 class student /类名为 student /声明字段private string id 。 private string name 。 private bool sex 。/声明属性public string IDgetreturn id 。s
29、etid=value 。public string Namegetreturn name 。setname=value 。public bool Sexgetreturn sex 。setsex=value。class Class1public void StudentF1(student ST1)/ 以对象 ST1 为形参 / 修改形参数据成员的值ST1.ID=56789 。ST1.Name= 张三 。ST1.Sex=true 。static void Main(string args)string SSex 。student S1。 / 声明一个学生类对象 S1S1=new student
30、( ) 。 /为 S1 分配内存空间S1.ID=12345 。S1.Name= 李平 。S1.Sex=false 。if (S1.Sex=true)SSex=男。elseSSex=女。Console.WriteLine( 学生学号 :+S1.ID+ 姓名 :+S1.Name+性别:+SSex)。/输出对象S1的值Class1 c=new Class1( ) 。/声明对象 c 以调用方法 StudentF1c.StudentF 1 (S 1 ) 。 /以对象 S1 为实参调用方法 if (S1.Sex=true)SSex=男。elseSSex=女。Console.WriteLine( 学生学号
31、:+S1.ID+ 姓名 :+S1.Name+ 性别 :+SSex) 。/输出对象 S1 的值Console.ReadLine( ) 。程序运行结果:学生学号: 12345 姓名:李平 性别:女学生学号: 56789 姓名:张三 性别:男结果的第一行为调用方法前对象 S1 的值,结果的第二行为调用方法后对象 S1 的值。虽 然在 Main 方法中并未对对象 S1 进行修改,但由于调用方法 StudentF1 时,将 S1 传递给了 ST1,而类对象参数是按引用传递的,所以在方法StudentF1中对ST1的修改,就是对 S1的修改,因此,结果的第二行, S1 的值发生了变化。4.3.3 重载方法
32、有时候方法实现的功能需要针对多种类型的数据,虽然C#有隐式转换功能,但这种转换在有些情况下会导致运算结果的错误,而有时数据类型无法实现隐式转换甚至根本无法转 换。例如:using System 。class Class1public 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) 。/调
33、用交换值方法Console.WriteLine( 交换后 A、 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#提供了方法重载机制。方法重载是声明两个以上的同名方法,实现对不同数据类型的相同处理。方法重载有两点要求:(
34、1) 重载的方法名称必须相同;(2) 重载的方法,其形参个数或类型必须不同,否则将出现“已经定义了一个具有相同类 型参数的方法成员”的编译错误。如果要使上例中的交换方法能同时处理整型与浮点型数据,重载的方法声明如下: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 void Swap(re
35、f int a,ref int b) ”方法,当执行“ c.Swap(ref fA,ref fB) 。”调用 时,系统会调用“ public void Swap(ref float a,ref float b) ”方法,从而实现对不同的数据 类型进行相同处理。【例 4-4 】创建一个控制台应用程序,在该程序中实现对两个整型、浮点型、双精度 型、十进制型与字符型数据比较大小的功能。using System 。namespace 方法重载 _比较值的大小class Class1/比较值大小的方法声明public int Max(int a, int b)return ab?a:b 。public
36、float Max(float a, float b) return ab?a:b 。 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 。 decima
37、l mA=8.2m,mB=9.8m 。 char cA=a,cB=b 。0,c.Max(iA,iB) 。0,c.Max(fA,fB) 。0,c.Max(dA,dB)0,c.Max(mA,mB)0,c.Max(cA,cB)Class1 c=new Class1( ) 。 Console.WriteLine(iA 与 iB 较大的值为: Console.WriteLine(fA 与 fB 较大的值为: Console.WriteLine(dA 与 dB 较大的值为: Console.WriteLine(mA 与 mB 较大的值为: Console.WriteLine(cA 与 cB 较大的值为:
38、Console.ReadLine( ) 。 程序运行结果为:iA 与 iB 较大的值为: 80 fA 与 fB 较大的值为: 8.8 dA 与 dB 较大的值为: 7.2 mA 与 mB 较大的值为: 9.8 cA 与 cB 较大的值为: b在上面的程序例题中,由于 float 类型可以隐式转换为 double 类型,因此比较 float 类型的 值大小的方法可以省略。 int 类型可以实现隐式转换,但由于 int 类型既可以隐式转换为 double 类型,也可以隐式转换为 decimal 类型,所以,比较 int 类型值大小的方法不能省 略,以免产生调用的二义性。4.4 构造函数构造函数是一
39、种特殊的方法成员,构造函数的主要作用是在创建对象(声明对象)时初 始化对象。一个类定义必须有至少一个构造函数,如果定义类时,没有声明构造函数,系统 会提供一个默认的构造函数,如果声明了构造函数,系统将不再提供构默认造函数。如果只有默认构造函数,在创建对象时,系统将不同类型的数据成员初始化为相应的默 认值,如,数值类型被初始化为0,字符类型被初始化为空格,字符串类型被初始化为null(空值),逻辑(bool)类型被初始化为false等。例如下面的程序:using System 。class student / 类名为 student/声明字段public string id 。public st
40、ring name 。public bool sex 。 public int age 。class Class1static void Main(string args)char SSex。 student S1=new student( ) 。if (S1.sex=true)SSex=男。elseSSex=女。Console.WriteLine( 学号: +S1.id+ 姓名: +S1.name + 性别: +SSex+ 年龄: 0,S1.age) 。Console.ReadLine( ) 。程序运行的结果为: 学号:姓名:性别:女年龄: 0这是因为系统将student类的数据成员id与n
41、ame初始化为null,将sex初始为false,将 age初始为0的缘故。如果想在创建对象时,将对象的数据成员初始为指定的值,则需要专门声明构造函数。4.4.1 声明构造函数声明构造函数与声明普通方法相比,有两个特别要求,一是构造函数不允许有返回类型包括 void 类型,二是构造函数的名称必须与类名相同。由于通常声明构造函数是为了在创建对象时,对数据成员初始化,所以构造函数往往需 要使用形参,例如参考前面的学生(stude nt )类,创建一个学生类对象时,需要给出学生的学号、姓名、性别及年龄等,所以学生类构造函数可以声明如下:public student(string ID,string
42、NAME,bool SEX,int AGE)id=ID 。name=NAME 。sex=SEX。age=AGE 。由于声明了上述带参数的构造函数,所以系统不再提供默认构造函数,这样在创建对象 时,必须按照声明的构造函数的参数要求给出实际参数,否则将产生编译错误,例如: student S2=new student(12345, 张三 ,true,21) 。由上述创建对象的语句可知, new 关键字后面实际是对构造函数的调用。 如果声明构造函数时使用的参数名称与类数据成员名称相同,则构造函数中使用的类数 据成员名称需要用关键字 this 引导,以免系统分不清形参与数据成员而产生二义性。将上例 中
43、的形参名称改为与数据成员同名的构造函数声明如下:public student(string id,string name,bool sex,int age)this.id=id 。=name 。this.sex=sex 。this.age=age。关键字 this 指所创建的对象,是声明对象时,由系统自动传递给构造函数的对象的引用形 参。事实上在调用类的非静态方法成员时,系统均会自动传递该引用形参,不过最好的办法 是使形参的名称与数据成员的名称有所区别。4.4.2 重载构造函数构造函数与方法一样可以重载,重载构造函数的主要目的是为了给创建对象提供更大的 灵活性,以满足创建对象
44、时的不同需要。例如,在创建一个学生(stude nt)对象时,有时可能需要只初始化姓名,而不初始化其他值,那么可以在前述声明构造函数的基础上再重载一 个只初始化姓名的构造函数,代码如下:public student(string NAME)name=NAME由于该构造函数与前述构造函数的参数个数不同,所以是一个合法的构造函数重载。有 了这个构造函数后,就可以声明只有一个实参的对象,例如:student S3=new student( 李平 ) 。如果在声明了带参数的构造函数后,还想保留默认构造函数,则必须显式声明一个默认 构造函数,显式声明的默认构造函数实际上是一个不实现任何功能的空函数。以
45、student 类 为例,声明默认构造函数如下:public student( )/ 显式声明默认构造函数【例 4-5】根据本节介绍内容,在控制台应用程序中创建 student 类,并声明构造函数及构造 函数的重载。using System 。namespace 构造函数class student / 类名为 student/声明字段public string id 。public string name 。public char sexx 。public bool sex 。public int age 。/声明构造函数public student( )/ 显式声明默认构造函数public
46、student(string id,string name,bool sex,int age) / 重载初始化学号、姓名、性别与年龄的构造函数this.id=id 。 =name 。 this.sex=sex 。 this.age=age。public student(string NAME)/ 重载只初始化姓名的构造函数name=NAME 。class Class1static void Main(string args)char SSex 。/声明无参对象(调用默认构造函数) student S1=new student( ) 。 if (S1.sex=true)SSex
47、=男。elseSSex=女。Console.WriteLine( 学号: +S1.id+ ,姓名: +S1.name + ,性别: +SSex+ ,年龄: 0,S1.age) 。/声明带学号、姓名、性别及年龄初始值的对象(调用四参数构造函 数)student S2=new student(12345, 张三 ,true,21) 。if (S2.sex=true)SSex=男。elseSSex=女。Console.WriteLine( 学号: +S2.id+ ,姓名: +S2.name + ,性别: +SSex+ ,年龄: 0,S2.age) 。/ 声明带姓名初始值的对象(调用一参数构造函数)
48、student S3=new student( 李平) 。if (S3.sex=true)SSex=男。elseSSex=女。Console.WriteLine( 学号: +S3.id+ ,姓名: +S3.name + ,性别: +SSex+ ,年龄: 0,S3.age) 。 Console.ReadLine( ) 。程序运行结果: 学号:,姓名:,性别:女,年龄: 0 学号: 12345 ,姓名:张三,性别:男,年龄: 21 学号:,姓名:李平,性别:女,年龄: 0由于构造函数的重载,程序中可以用不同的初始化方式声明对象,为创建对象提供了灵 活性。4.5 静态成员类可以具有静态成员,例如静态
49、字段、静态方法等。4.5.1 静态数据成员与方法成员静态成员与非静态成员的不同在于,静态成员属于类,而非静态成员则总是与特定的实 例(对象)相联系。声明静态成员需要使用 static 修饰符。1. 静态数据成员 非静态的字段(数据)总是属于某个特定的对象,其值总是表示某个对象的值。例如, 当说到学号( ID )时,总是指某个学生的学号,而不可能是全体学生的学号,相应的,在 前面定义的student类的id成员就是一个非静态的数据成员。有时可能会需要类中有一个数据成员来表示全体对象的共同特征,例如在student 类用一个数据成员来统计学生的人数,那么这个数据成员表示的就不是某个学生对象的特征,
50、而是 全体学生对象的特征,这时就需要使用静态数据成员。例如:class student / 类名为 studentpublic static int studentnumber 。 / 声明静态数据成员public string id 。public string name 。public char sexx 。public bool sex 。 public int age 。静态数据成员 studentnumber 不属于任何一个特定的对象,而是属于类,或者说属于全体 对象,是被全体对象共享的数据。2. 静态方法 非静态的方法包括非静态的构造函数总是对某个对象进行数据操作,例如,比较值的大
51、 小方法,总是某个对象的比较值大小的方法,相应的,在前述的例子中类Class1 中 Max 方法成员就是一个非静态的方法成员。如果某个方法使用时并不需要与具体的对象相联系,例如方法操作的数据并不是某个具 体对象的数据而是表示全体对象特征的数据,甚至方法操作的数据与对象数据根本无关,这 时可以将该方法声明为静态方法。例如要操作前述student 类例子中的静态数据成员studentnumber ,则应该声明一个静态方法。静态方法同样使用修饰符 static 声明,静态方法属于类,只能使用类调用,不能使用对象 调用。【例 4-6】创建一个控制台应用程序,在该程序中定义一个学生类,该类除包含非静态成
52、员 外,还包含一个静态数据成员用以统计学生人数(对象个数),一个静态方法用以返回学生 人数。using System 。 namespace 静态成员 class student / 类名为 student/声明字段public static int studentnumber 。 / 声明静态数据成员 public string id 。 public string name 。 public char sexx 。public bool sex 。public int age 。public student(string id,string name,bool sex,int age) /
53、 声明构造函数 studentnumber+ 。 / 每创建一个对象,静态数据成员增 1 this.id=id 。=name 。 this.sex=sex 。 this.age=age。public static int GetNumber( ) / 声明静态方法 return studentnumber 。class Class1static void Main(string args) char SSex 。 student S1=new student(12345, 张三 ,true,21) 。 / 声明对象 S1 if (S1.sex=true)SSex=男。elseSSex=女。Console.WriteLine( 学号: +S1.id+ ,姓名: +S1.name+ ,性别: +SSex+ ,年龄: 0,S1.age) 。 student S2=new student(23456, 李四 ,false,20) 。/ 声明对象 S2if (S2.sex=true)SSex=男。elseSSex=女。Console.WriteLine( 学号: +S2.id+ ,姓名: +S2.name+ ,性别: +SSex+
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年中相微乳液驱纳米驱油剂提采技术
- 甘南市重点中学2025-2026学年初三下学期第一次联考生物试题试卷含解析
- 2026年公共数据提供单位收益激励与数据质量提升联动机制
- 2026年无线基站天线PCB等传统设备商及车联网卫星导航模组厂受益方向
- 2026年低空目标探测中的多普勒频移应用
- 2026年RTCP功能含义与机床结构参数标定方法
- 人力资源管理师职称评定指南
- 金融分析师面试问题探讨
- 记者招聘面试指南及问题详解
- 新零售平台运营经理面试全解析与技巧
- 抚育林施工方案(3篇)
- 【初中 物理】二力平衡课件-2025-2026学年人教版物理八年级下册
- 【华信咨询】中国智算中心(AIDC)产业发展白皮书(2024年)
- 2026年及未来5年市场数据中国吡咯喹啉醌PQQ行业发展潜力分析及投资战略数据分析研究报告
- 重建祠堂施工方案(3篇)
- 酒店餐厅外包协议书
- 2026年湖南城建职业技术学院单招职业技能测试模拟测试卷附答案
- 燃气管道安装质量控制管理措施
- 2025年公安专业科目考试真题及答案
- 儿童肥胖疾病科普
- 水电预埋施工流程方案
评论
0/150
提交评论