1第4章面向对象编程技术面向对象的程序设计方法是当前程序设计的大势所趋。面向对象的程序设计方法是对结构化程序设计方法的重新认识。在程序的设计中,方法总是与特定的数据结构密切相关的,方法含有对数据结构的访问,特定的方法只适用于特定的数据结构,因此方法与数据结构在编程中应该是一个密不可分的整体,这个整体叫对象。C#通过类、对象、继承、多态等机制形成一个完善的面向对象的编程体系。4.1类和对象类是C#程序设计的基本单位。4.1.1类和对象概述现实生活中的类是人们对客观对象不断认识而产生的抽象的概念,而对象则是现实生活中的一个个实体。例如,人们在现实生活中接触了大量的汽车、摩托车、自行车等实体,从而产生了交通工具的概念,交通工具就是一个类,而现实生活中的具体的汽车、摩托车自行车等则是该类的对象。面向对象程序设计的类从本质上和人们现实生活中的这一认识过程是相同的。例如在编程实践中,人们经常使用按钮这一控件,每一个具体的按钮是一个按钮对象,而按钮类则是按钮对象的抽象,并且人们把这一抽象用计算机编程语言表示为数据集合与方法集合的统一体,然后再用这个类创建一个个具体的按钮对象。可以把类比作一种蓝图,而对象则是根据蓝图所创建的实例,可以把类比作生产模具,而对象则是由这种模具产生的实例(产品)。所以人们又把对象叫做类的实例。类是对事物的定义,而对象则是该事物本身。在VisualStudio.NET集成环境中的,工具箱中的一个个控件,是被图形文字化的可视的类,而把这些控件添加到窗体设计器中后,窗体设计器中的控件则是对象,即由工具箱中的类创建的对象。类是一种数据类型,在C#中,类这种数据类型可以分为两种:一种是由系统提供的预先定义的,这些类在.NET框架类库中;一种是用户定义数据类型。在创建对象之前必须先定义该对象所属的类。然后由类声明对象。类本质上是一种数据类型,所以类的用法与基本数据类型的用法基本相同,事实上,在VisualStudio.NET中像int、float等基本数据类型也是特殊的类。那么,用基本数据类型可以声明变量,用类类型也可以声明变量,只不过类类型的变量叫类的对象或类的实例。4.1.2类定义类定义的格式与结构定义的格式相似,在类定义中需要使用关键字class,其简单的定义2格式为:class〈类名〉{类体}“类名”是一个合法的C#标识符,表示数据类型(类类型)名称,“类体”以一对大括号开始和结束,在一对大括号后面可以跟一个分号。例如:classstudent//类名为student{publicstringID;publicstringName;publicboolSex;}上例中,定义了一个名为“student”(学生)的类,类体中包括学生的学号(“ID”)、姓名(“Name”)与性别(“Sex”)。在上例的“类体”中声明的数据都使用“public”修饰,“public”(公共的)表示这些数据可以直接进行访问。如果仅从“student”类的定义形式看,其与结构类型除了关键字外几乎没有任何差别。当然这只是为了说明问题方便,这种定义方式并不符合面向对象程序设计的原则,因为类中缺少了对数据的操作。“类体”包括类中的所有数据及对数据的操作,面向对象程序设计将数据与对数据的操作作为一个整体,以类的形式进行定义,这种机制叫“封装”。在“类体”中,所有的数据及对数据的操作的集合叫类成员,类成员的种类很多,本章仅介绍“字段”、“属性”、“方法”与“构造函数”。“字段”是类定义中的数据,也叫类的变量。在上例中定义的“ID”、“Name”与“Sex”等均为类中的字段。“属性”用于读取和写入“字段”值,“属性”是字段的自然扩展,对用户而言,“属性”等同于“字段”本身,对程序员而言,属性是一种读写“字段”的特殊方法。“方法”实质上就是函数,用于对字段进行计算和操作,即对类中的数据进行操作,以实现特定的功能。4.1.3声明与使用对象定义类之后,可以用定义的类声明对象,声明对象后可以访问对象成员。每一个类对象均具有该类定义中的所有成员,正如每一个整型变量均可以表示同样的数值范围一样。1.声明对象声明对象的格式与声明基本数据类型的格式相同:类名对象名;例如:studentS1;//声明一个学生类对象S1但是,对象声明后,需用“new”关键字进行初始化,这样才能为对象在内存中分配保存数据的空间。初始化的格式:3对象名=new类名();例如:S1=newstudent();//为S1分配内存空间可以将声明与初始化对象合二为一,例如:studentS1=newstudent();//声明对象并初始化2.访问对象访问对象实质是访问对象成员,对对象变量成员的访问与结构变量相同,使用“.”运算符。例如:S1.ID=12345;S1.Name=张三;S1.Sex=true;上面的代码为对象S1数据成员赋值。可以使用对象变量为另一对象变量整体赋值,例如,“studentS2;S2=S1;”或“studentS2=S1;”。这时,不需要使用new关键字对“S2”初始化。可以使用对象中的某一成员。例如:stringsName=S1.Name;//将对象S1的Name成员值赋给字符串变量sName4.1.4值类型与引用类型类定义的类型与结构定义的类型虽然相似,但这两种类型却有很大的差别,这涉及到C#中变量存储方式的问题。从变量的存储方式看,C#中的变量可以分为值类型变量与引用类型变量。1.值类型值类型变量直接包含其本身的数据,因此每个值类型变量本身就包含有赋给它的值。在C#中,内置数据类型除了字符串(string)类型与对象(object)类型外其余均为值类型。枚举类型与结构类型也是值类型。例如“intX=42;”,整型变量X就是值类型。2.引用类型与值类型不同,引用类型变量不包含本身的数据,只是存储对数据的引用,数据保存在内存的其他位置。例如:usingSystem;classClass1{classTest{publicintA;}staticvoidMain(string[]args){intX=42,Y=X;TestT1=newTest();4T1.A=42;TestT2=T1;Y=100;T2.A=100;}}引用类型与值类型在内存中的存储形式如图4-1所示。intX=42;42T1.A=42;42的引用42图4-1值类型与引用类型的存储值类型变量可以使用变量来赋值,引用类型变量也可以使用变量来赋值。例如上例中的代码:intX=42,Y=X;TestT1=newTest();T1.A=42;TestT2=T1;//使用对象变量赋值但是,值类型与引用类型用变量赋值的性质却不同,如图4-2所示。intX=42;intY=X;4242T1.A=42;42的引用42TestT2=T1;42的引用图4-2值类型与引用类型用变量赋值从图中可以看到,用变量“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进行修饰,public叫访问修饰符。声明类中的成员时,使用不同的访问修饰符,表示对类成员的访问权限不同,或者说访问修饰符确定了在什么范围可以访问类成员。5C#中最常用的访问修饰符及其意义,如表4-1所示。表4-1访问修饰符访问修饰符意义public(公有)访问不受限制,可以被任何其他类访问private(私有)访问只限于含该成员的类,即只有该类的其他成员能访问protected(保护)访问只限于含该成员的类、及该类的派生类在类定义中,如果声明成员没有使用任何访问修饰符,则该成员被认为是私有(private)的。如果不涉及继承,private与protected没有什么区别。在类定义中,如果成员被声明为private或protected,则不允许在类定义外使用点运算符访问,即在类定义外,点运算符只能访问public成员。例如在下面的类定义中:classstudent//类名为student{privatestringID;//私有publicstringName;//公有protectedboolSex;//保护}studentS1=newstudent();S1.ID=12345;//非法,ID为privateS1.Name=张三;//合法,Name为publicS1.Sex=true;//非法,Sex为protected在类定义外使用点运算符访问“ID”与“Sex”是非法的,而访问“Name”则是合法的,因为“ID”与“Sex”是private或protected的,而“Name”则是public的。通常,在类定义中,数据成员(字段)被声明为private或protected,从而实现所谓的数据隐藏,以确保不能在类外随意访问类的数据成员;而其他种类的成员则被声明为public,以通过这些成员实现对类的数据成员的访问。4.2属性对私有或保护数据成员常见的访问是读取与设置修改数据值,在类定义外部,这种访问可通过属性成员实现。通过属性可以控制对数据的访问方式,甚至设置数据可接受的值域。4.2.1声明属性在类定义中声明属性的格式为:访问修饰符类型属性名{}可以将属性声明为读写属性、只读属性或只写属性。1.声明读写属性修改student类定义添加属性声明:classstudent//类名为student{6//声明字段privatestringid;privatestringname;privateboolsex;//声明属性publicstringID{get{returnid;}set{id=value;}}publicstringName{get{returnname;}set{name=value;}}publicboolSex{get{returnsex;}set{sex=value;}}}在属性声明中,get与set叫属性访问器。get完成对数据值的读取,return用于返回读取的值;set完成对数据值的设置修改,value是一个关键字,表示要写入数据成员的值。属性名应和其要访问的数据成员名相关但不相同,可以采取数据成员名全用小写,而属7性名的单词首字母大写的方式,如数据成员名为name,则对应的属性名为Name。2.声明只读或只写属性在属性声明中,如果只有get访问器,则该属性为只读属性。例如:publicboolSex{get{returnsex;}}只读属性意味着,数据成员的值是不能被修改的。在属性声明中如果只有set访问器,则该属性为只写属性。只写属性在程序设计中不常使用。4.2.1使用属性属性成员的使用就如同公有数据成员的使用一样。可以为可写的属性赋值,可以用可读的属性为其他变量赋值。以student类为例:studentS1=newstudent();//用属性设置修改数据成员值S1.ID=12345;S1.Name=张三;S1.Sex=true;//用属性读取数据成员值为其他变量赋值boolSSex=S1.Sex;如果属性为只读的,则属性不能出现在赋值运算符的左边。在C#程序设计中,窗体与控件的属性就是这类成员,其中在属性窗口显示的属性,均为可读写属性,窗体与控件的只读属性只能在代码中使用。4.3方法方法是把一些相关的语句组织在一起,用于解决某一特定问题的语句块。方法必须放在类定义中。方法同样遵循先声明后使用的规则。4.3.1声明与调用方法方法的使用分声明与调用两个环节。1.声明方法声明方法最常用的格式:访问修饰符返回类型方法名(参数列表){}方法的访问修饰符通常