C#程序设计实用教程_第1页
C#程序设计实用教程_第2页
C#程序设计实用教程_第3页
C#程序设计实用教程_第4页
C#程序设计实用教程_第5页
已阅读5页,还剩156页未读 继续免费阅读

下载本文档

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

文档简介

第5章

面向对象程序设计基础2010-11-19面向对象的软件开发技术是当今计算机技术发展的重要成果和趋势之一。C#是完全面向对象的程序设计语言。类和对象是面向对象程序设计中的重要概念。封装性、继承性和多态性是面向对象的特点。本章主要介绍面向对象程序设计中的基本概念和基于C#的面向对象程序设计的方法。2023/2/42C#程序设计实用教程基本概念

5.1面向对象概述

5.1.1面向对象的概念面向对象程序设计(Object-OrientedProgramming)简称OOP技术。面向对象编程技术是计算机编程技术中一次重大的进步。在面向对象编程技术出现之前,程序的设计普遍采用的是面向过程的程序设计方法。2023/2/43C#程序设计实用教程5.1.1面向对象的概念OOP是一种系统化的程序设计方法,强调直接以问题域(即现实世界)中的事物为中心来考虑问题,并按照这些事物的本质特征把它们抽象为对象。OOP的主要思想是将数据及处理这些数据的操作都封装(Encapsulation)到一个称为类(Class)的数据结构中。使用这个类时,只需要定义一个类的变量即可,这个变量(Object)。通过调用对象的数据成员完成对类的使用。在这种方法下,编程人员不需要过分关注“如何做”,而是重点关注“做什么”。OOP编程思想较好地适应了现实世界中的问题,因而得以广泛应用。2023/2/44C#程序设计实用教程5.1.2面向对象语言的特点

面向对象的编程方式具有继承、封装和多态性等特点。(1)继承在生活中,事物有很多的相似性,这种相似性是人们理解纷繁事物的一个基础。因为事物之间往往具有某种“继承”关系。比如,儿子和父亲往往有许多相似之处,因为儿子从父亲那里遗传了许多特性;2023/2/45C#程序设计实用教程5.1.2面向对象语言的特点

继承(inheritance)是面向对象编程技术的一块基石,通过它可以创建分等级层次关系的类。继承是父类和子类之间共享数据和方法的机制,通常把父类称为基类,子类称为派生类。子类可以从其父类中继承属性和方法,通过这种关系模型可以简化类的设计。。2023/2/46C#程序设计实用教程5.1.2面向对象语言的特点

例如,可以将水果看作一个父类,那么水果类具有颜色属性。然后再定义一个香蕉类,在定义香蕉类时就不需要定义香蕉类的颜色属性,通过如下继承关系可以使香蕉类具有颜色属性。class水果类{ Public颜色;//在水果类中定义颜色属性}class香蕉类

:水果类{ //香蕉类中其他的属性和方法}2023/2/47C#程序设计实用教程水果类颜色水果类颜色香蕉类香蕉类的其它属性和方法5.1.2面向对象语言的特点

(2)封装类是属性和方法的集合,为了实现某项功能而定义类后,开发人员并不需要了解类体内每行代码的具体涵义,只需通过对象来调用类内某个属性或方法即可实现某项功能,这就是类的封装。封装提供了外界与对象进行交互的控制机制,设计和实施者可以公开外界需要直接操作的属性和方法,而把其他的属性和方法隐藏在对象内部。这样可以让软件程序封装化,而且可以避免外界错误地使用属性和方法。2023/2/48C#程序设计实用教程5.1.2面向对象语言的特点

(3)多态性类的多态(polymorph)指对于属于同一个类的对象,在不同的场合能够表现出不同的特征。多态性主要指在一般类中定义的属性或行为,被特殊类继承之后,可以具有不同数据类型或表现出不同的行为。这使得同一个属性或行为在一般类及其各个特殊类具有不同的意义。例如:某个对象,其基类为“笔”,在调用它的“写”方法时,程序会自动判断出它的具体类型,如果是毛笔,则调用毛类对应的“写”方法,如果是铅笔,则调用铅笔对应的“写”方法。2023/2/49C#程序设计实用教程

5.2定义类

在C#中,“类”是一种数据结构,它可以包含数据成员(常量和字段)、函数成员(方法、属性、事件、索引器、运算符、构造函数、析构函数)。类是个静态的概念,如果要使用某个类,就应该定义该类的一个或多个实例,每一个实例就是一个对象。2023/2/410C#程序设计实用教程

5.2.1类的概念

类是对象概念在面向对象编程语言中的反映,是相同对象的集合。类描述了一系列在概念上有相同含义的对象,并为这些对象统一定义了属性和方法。类是对象的抽象描述和概括。例如:汽车是一个类,只要是汽车都有车牌,颜色,车轮、车门、发动机等特性,都可以加速,刹车,转方向等行为。这是将所有的汽车进行归纳之后得出的共有的特性,但这些特性都是抽象的,非常不具体,只是用来描述一个类别,并不能具体指一辆汽车。而具体到某辆汽车就是一个对象了,例如:车牌照为苏A2345**的黑色奥迪轿车,这就是汽车类的一个汽车对象。用具体的属性可以在汽车类中唯一确定自己,并且对象具有类的操作2023/2/411C#程序设计实用教程

5.2.1类的概念

在C#中,所有的内容都被封装在类中,类是C#的基础,每个类通过属性和方法及其他一些成员来表达事物的状态和行为。事实上,编写C#程序的主要任务就是定义各种类及类的各种成员。2023/2/412C#程序设计实用教程

5.2.2类的声明

简单地讲,类是一种数据结构,用于模拟现实中存在的对象和关系,包含静态的属性和动态的方法。下面来看如何声明类及其属性、方法。在声明一个类之前,需要向工程中新添加一个文件。2023/2/413C#程序设计实用教程

5.2.2类的声明

1.向工程添加新项目在VS.NET中添加一个新的类文件以及其他新项目。操作很简单,具体步骤如下:(1)在【解决方案浏览器】视图中,在工程上单击右键,再在打开的快捷菜单中选择【添加】→【类】,如图5-1所示。2023/2/414C#程序设计实用教程

5.2.2类的声明

(2)在此时弹出的对话框中选择添加类文件,并为新文件命名,以.cs作为后缀,如图5-2所示。(3)单击【打开】按钮后,就可以在【解决方案浏览器】视图中看到这个新的类文件了。(4)双击该类文件,可以在其中声明新的类。当然,也可以把多个功能类似的类放在一个类文件中。2023/2/415C#程序设计实用教程

5.2.2类的声明

2.声明类C#中类的声明需要使用class关键字,并把类的主体放在花括号中,格式如下:[类修饰符]class类名

[:基类类名]{ //属性 //方法}其中,除了class关键字和类名外,剩余的都是可选项;类名必须是合法的C#标识符,它将作为新定义的类的类型标识符。2023/2/416C#程序设计实用教程

5.2.2类的声明

注意:class关键字前面是访问级别。在C#中,类的访问级别由类的修饰符进行限定,类的修饰符如表5-1所示。在上例中,如果类的修饰符为public,这表示该类可以被任何其他类访问。类的名称位于class关键字的后面。2023/2/417C#程序设计实用教程

5.2.2类的声明

以上的类修饰符可以两个或多个组合起来使用,但需要注意下面几点:(1)

在一个类声明中,同一类修饰符不能多次出现,否则会出错。。2023/2/418C#程序设计实用教程

5.2.2类的声明

(2)在使用public、protected、internal和private这些类修饰符时,要注意这些类修饰符不仅表示所定义类的访问特性,而且还表明类中成员声明中的访问特性,并且它们的可用性也会对派生类造成影响。(3)如果省略类修饰符,则默认为私有修饰符private。(4)对于具有继承关系的类才有基类。如果一个类没有从任何类继承,就不需要基类类名选项。在C#中,一个类只能从另一个类中继承。2023/2/419C#程序设计实用教程

5.2.2类的声明

下面以一个学生类的实例,说明该类在C#中的实现。该类的类图如图5-3所示。【例5-1】定义一个学生类。publicclassStudent{//属性//学号、姓名、年龄等

//方法//长大、入学、毕业等}

2023/2/420C#程序设计实用教程

5.2.3类的静态特性

属性(或字段)可以看作是类的静态描述,同样,在定义属性时,也可以使用访问修饰符来定义其访问级别。属性的定义格式如下:

[修饰符]数据类型属性名;其中,属性修饰符attribe-modifier包括public、private、protected。下面的例子用来说明public和private修饰符的作用。

2023/2/421C#程序设计实用教程

5.2.3类的静态特性

2023/2/422C#程序设计实用教程【例5-2】public和private修饰符的作用。usingSystem;

namespaceExample_PublicAndPrivate{///学生类publicclassStudent{

//属性

publicstringstrName;//公有属性

privateintnAge; //私有属性

//方法...}///Main函数类classTest{///应用程序的主入口点。staticvoidMain(string[]args){Students=newStudent();s.strName="张三“;//正确s.nAge=20;//错误,不能访问}}}

5.2.3类的静态特性

上述程序中,定义一个Student类,包含一个公有属性“strName”和一个私有属性“nAge”。在Test类中,试图对学生类的对象s的年龄进行设置,但是Student类的nAge属性是私有的,在其他的类中无法访问,因此程序会报错,报错信息如图5-4所示。而访问其公有属性strName就不会有问题。2023/2/423C#程序设计实用教程

5.2.4类的动态行为:方法

类的属性是客观世界实体性质的抽象,而方法是实体所能执行的操作。下面来看如何声明其动态方法。同属性一样,类的方法也具有访问属性,如public、private、protected等,其定义格式如下:

[修饰符]返回类型方法名(参数列表);下面的例子为Student类定义了公有方法SetAge()和GetAge(),用于设置和获取其静态属性“年龄”。2023/2/424C#程序设计实用教程

5.2.4类的动态行为

【例5-3】类的公有方法的示例。usingSystem;

namespaceDeclareMethod{///学生类publicclassStudent{//属性

publicstringstrName; //公有属性privateintnAge; //私有属性

//方法...publicvoidSetAge(int_nAge){this.nAge=_nAge;}

2023/2/425C#程序设计实用教程

5.2.4类的动态行为

publicintGetAge(){returnthis.nAge;}}

///Main函数类classClass1{staticvoidMain(string[]args){Students=newStudent();s.SetAge(20);

//赋值年龄Console.WriteLine(s.GetAge()); //获取年龄}}}2023/2/426C#程序设计实用教程

5.2.4类的动态行为

程序中为各个学生定义了公有方法SetAge(),其功能是为类的私有属性“年龄”赋值;同时为学生类定义了获取“年龄”属性值的公有方法GetAge()。通过SetAge()方法,并传递适当的参数,便可以为学生s的年龄赋值,而通过调用GetAge()方法获取其年龄,并输出。2023/2/427C#程序设计实用教程

5.2.5创建类的实例-对象

类是现实世界中对象或者关系的模拟,是一个抽象的概念。例如,像“学生”这个概念,世界上并没有一个叫做“学生”的活生生的东西,而只有“张三”或者“李四”这些具体的学生实例,这反应了类和对象的关系。(1)类是具有相同或相似结构、操作和约束规则的对象组成的集合。(2)对象是某一类的具体化实例,每一个类都具有某些共同特征对象的抽象。C#使用new关键字来实现实例化类得到一个具体的对象,其格式如下:

类名对象名=new类名([参数列表]);在前面的示例中已经用到创建类实例,都是使用new关键字得到一个具体的学生对象。如下列代码所示:

Students=newStudent();2023/2/428C#程序设计实用教程对象的使用【例5-2】public和private修饰符的作用。usingSystem;

namespaceExample_PublicAndPrivate{///学生类publicclassStudent{

//属性

publicstringstrName;//公有属性

privateintnAge; //私有属性

//方法...}///Main函数类classTest{///应用程序的主入口点。staticvoidMain(string[]args){Students=newStudent();s.strName="张三“;//正确s.nAge=20;//错误,不能访问}}}

5.2.6继承类

继承的本质是代码重用。当要构造一个新的类时,通常无需从头开始。例如,在学生类的基础上,可以建立一个“大学生”类。很明显,“大学生”这个类具有自己的新特点,如“所在系”就并不是所有的学生都有的,而是大学生才有的特殊性质。因此,可以把大学生看作是学生的一种延续,即在继承了学生的属性和方法基础之上,又包含了新的属性或方法。在构造大学生这个类时,只需在学生类的基础上添加大学生特有的特性即可,而无需从头开始。此时,称学生类为父类,大学生类为子类。在C#中,用符号“:”来实现类的继承。2023/2/430C#程序设计实用教程

5.2.6继承类

【例5-4】类继承的示例。usingSystem;

namespaceExample_Inheritance{ ///学生类 publicclassStudent{publicstringstrName; //姓名publicintnAge; //年龄}

2023/2/431C#程序设计实用教程

5.2.6继承类

///大学生类:继承学生类publicclassCollegeStudent:Student{publicstringstrInsititute; //所在系

}

2023/2/432C#程序设计实用教程

5.2.6继承类

///程序入口:主函数类publicclassMainClass{///主函数staticvoidMain(string[]args){Students=newStudent();s.strName="xiaobao";s.nAge=18;Console.WriteLine("姓名:{0},年龄{1}",s.strName,s.nAge);

2023/2/433C#程序设计实用教程

5.2.6继承类

//使用子类Console.WriteLine("-------------使用子类-------------");CollegeStudentc=newCollegeStudent();c.strName="小宝";c.nAge=23;c.strInsititute="计算机系";Console.WriteLine("姓名:{0},年龄:{1}岁,所属系:{2}",c.strName,c.nAge,c.strInsititute);Console.ReadKey();}}}2023/2/434C#程序设计实用教程

5.2.6继承类

程序运行结果如图5-5所示。注意:此时,大学生类具有学生类的所有属性和方法,另外,还具有其独自的属性——所在系。不难看出,继承就是指一个子类能够直接获得父类的性质或特征,而不必重复定义。显然,继承具有传递性。另外,C#只支持单继承,即一个类只能继承一个父类。2023/2/435C#程序设计实用教程

5.3构造函数和析构函数

在实际应用中,方法的定义和调用是很复杂的。在此,将从两个特殊的方法(构造函数和析构函数)入手,对其进行进一步的讨论。在C#中,构造函数是当类实例化时首先执行的函数。反之,析构函数是当实例(也就是对象)从内存中销毁前最后执行的函数。这两个函数的执行是无条件的,并且不需要程序手工干预。也就是说,只要定义一个对象或销毁一个对象,不用显式地调用构造函数或析构函数,系统都会自动在创建对象时调用构造函数,而在销毁对象时调用析构函数。2023/2/437C#程序设计实用教程

5.3.1构造函数

在实例化对象的时候,对象的初始化是自动完成的,并且这个对象是空的。有时,我们希望创建一个对象时要为其初始化某些特征,这时就需要用到构造函数。在C#中,构造函数是特殊的成员函数。构造函数的特殊性表现在如下几个方面:(1)构造函数的函数名和类的名称一样。(2)构造函数可以带参数,但没有返回值。(3)构造函数在对象定义时被自动调用。2023/2/438C#程序设计实用教程

5.3.1构造函数

(4)如果没有给类定义构造函数,则编译系统会自动生成一个默认的构造函数。(5)构造函数可以被重载,但不可以被继承。(6)构造函数的类型修饰符总是public。如果是private,则表示这个类不能被实例化,这通常用于只含有静态成员的类中。2023/2/439C#程序设计实用教程

5.3.1构造函数

【例5-5】通过构造函数,实现在产生一个学生对象时为其完成起名工作。usingSystem;

namespaceExample_Construct{///<summary>///学生类///</summary>publicclassStudent{publicstringstrName; //域

2023/2/440C#程序设计实用教程

5.3.1构造函数

///<summary>///构造函数,为学生起名///</summary>publicStudent(string_strName){this.strName=_strName;}

}classClass1{

staticvoidMain(string[]args){Students=newStudent("张三");Console.WriteLine(s.strName);}}}2023/2/441C#程序设计实用教程

5.3.1构造函数

注意:在Student类中,定义了方法Student(),注意这个方法与Student类同名。这样,每当实例化一个Student对象时,总会执行这个函数。在构造函数中可以没有参数,也可以有一个或多个参数。这表明构造函数在类的声明中可以有函数名相同,但参数个数不同或者参数不同的多种形式,这就是构造函数重载。用new关键字创建一个类的对象时,类名后的一对圆括号提供初始化列表,这实际上就是提供给构造函数的参数。系统根据这个初始化列表的参数个数、参数类型和参数顺序调用不同的构造函数。2023/2/442C#程序设计实用教程

5.3.1构造函数

【例5-6】实现Time类的构造函数及其重载。usingSystem;

namespaceExample_ConstructOverload{classTime{publicintnHour,nMinute,nSecond;publicTime(){nHour=nMinute=nSecond=0;}

2023/2/443C#程序设计实用教程

5.3.1构造函数

publicTime(intHour){nHour=Hour;nMinute=nSecond=0;}publicTime(intHour,intMinute){nHour=Hour;nMinute=Minute;nSecond=0;}2023/2/444C#程序设计实用教程

5.3.1构造函数

publicTime(intHour,intMinute,intSecond){nHour=Hour;nMinute=Minute;nSecond=Second;}}classTest{staticvoidMain(){Timet1,t2,t3,t4;2023/2/445C#程序设计实用教程

5.3.1构造函数

//对t1,t2,t3,t4分别调用不同的构造函数t1=newTime();t2=newTime(10);t3=newTime(10,30);t4=newTime(10,30,30);Console.WriteLine("t1的时间为:{0}时{1}分钟{2}秒",t1.nHour,t1.nMinute,t1.nSecond);Console.WriteLine("t2的时间为:{0}时{1}分钟{2}秒",t2.nHour,t2.nMinute,t2.nSecond);Console.WriteLine("t3的时间为:{0}时{1}分钟{2}秒",t3.nHour,t3.nMinute,t3.nSecond);Console.WriteLine("t4的时间为:{0}时{1}分钟{2}秒",t4.nHour,t4.nMinute,t4.nSecond);}}}2023/2/446C#程序设计实用教程

5.3.1构造函数

程序运行结果如图5-6所示。注意:实例对象创建时,根据不同的参数调用相应的构造函数完成初始化。2023/2/447C#程序设计实用教程

5.3.2析构函数

前面,介绍了使用构造函数在实例化对象时自动完成一些初始化工作。反之,在销毁对象时,有时候也希望能自动一些做“收尾”任务,例如关闭数据库连接等。C#使用析构函数来完成这个功能。2023/2/448C#程序设计实用教程

5.3.2析构函数

析构函数也是类的特殊的成员函数,它主要用于释放类实例。析构函数的特殊性表现在以下几个方面:(1)析构函数的名字也与类名相同,只是需要在其前面加了一个符号“~”。(2)析构函数不接收任何参数,没有任何返回值,也没有任何访问关键字。(3)当撤销对象时,自动调用析构函数。(4)析构函数不能被继承,也不能被重载。注意:另外,如果试图声明其他不与类名相同,但是以“~”开头的方法,编译器会产生错误。2023/2/449C#程序设计实用教程

5.3.2析构函数

【例5-7】为Student类建立析构函数。publicclassStudent{///<summary>///析构函数///</summary>~Student(){Console.WriteLine("CallDestructMethod.");}}当程序使用完一个学生对象后,都会自动调用这个析构函数,输出“CallDestructMethod.”。2023/2/450C#程序设计实用教程

5.3.2析构函数

说明:事实上,一般并不需要使用析构函数,.NETFramework提供了默认的析构函数执行内存清理等工作。如果确定需要在销毁对象前,完成一些特殊的任务,才需要使用自定义的析构函数。2023/2/451C#程序设计实用教程

5.3.2析构函数

【例5-8】构造函数和析构函数的使用。usingSystem;

namespaceExample_ConstructAndDestruct{classPoint{intx,y,z;publicPoint(){this.z=0;}2023/2/452C#程序设计实用教程

5.3.2析构函数

publicPoint(intx,inty){this.x=x;this.y=y;this.z=x+y;}publicint_Z //属性{get{returnthis.z;}set{this.z=value;}}2023/2/453C#程序设计实用教程

5.3.2析构函数

~Point(){Console.WriteLine("~Point()isbeingcalled.");}}classTest{staticvoidMain(){Pointp1=newPoint(1,5);Pointp2=newPoint();Console.WriteLine("p1.z="+p1._Z);Console.WriteLine("p2.z="+p2._Z);}}}2023/2/454C#程序设计实用教程

5.4方法

在前面,对类的方法进行了简单的介绍,也对特殊的类方法——构造和析构函数进行了介绍。在实际应用中,方法的定义和调用要复杂得多。本节将从输入参数、方法重载等方面,对其进行进一步的讨论。2023/2/455C#程序设计实用教程

5.4.1方法的定义及调用

方法是类中用于执行计算或进行其他操作的函数成员。1.方法的定义方法由方法头和方法体组成,其一般定义的格式为:修饰符返回值类型方法名(形式参数列表){

方法体各语句;}2023/2/456C#程序设计实用教程

5.4.1方法的定义及调用

说明:(1)如果省略“方法修饰符”,默认为private,表示该方法为类的私有成员。(2)“返回值类型”指定该方法返回数据的类型,它可以是任何有效的类型,C#通过方法中的return语句得到返回值。如果方法不需要返回一个值,其返回值类型必须是void。(3)方法名要求满足C#标识符的命名规则,括号()是方法的标志,不能省略。(4)“方法参数列表”是逗号分隔的类型、标识符对。这里的参数是形式参数,本质是一个变量,它用来在调用方法时接收传给方法的实际参数的值。如果方法没有参数,那么参数列表为空。2023/2/457C#程序设计实用教程

5.4.1方法的定义及调用

【例5-9】方法的定义。classMotorcycle{publicvoidStartEngine(){}publicvoidAddGas(intgallons){}publicintDrive(intmiles,intspeed){return0;}}2023/2/458C#程序设计实用教程

5.4.1方法的定义及调用

2.方法的调用调用对象的方法类似于访问字段。在对象名称名称之后,依次添加句点、方法名称和括号。参数在括号内列出,并用逗号隔开。因此,可以如下例来调用Motorcycle类的方法。【例5-10】方法的调用。Motorcyclemoto=newMotorcycle();moto.StartEngine();moto.AddGas(15);moto.Drive(5,20);2023/2/459C#程序设计实用教程

5.4.1方法的定义及调用

3.从方法返回一般来说有两种情况将导致方法返回。(1)当遇到方法的结束花括号。(2)执行到return语句。有两种形式的return语句:一种用在void方法中(即无需有返回值的方法),另一种用在有返回值的方法中。2023/2/460C#程序设计实用教程

5.4.1方法的定义及调用

【例5-11】通过方法的结束花括号返回。usingSystem;

namespaceMethod{classMyClass{publicvoidmyMethod(){inti;for(i=0;i<10;i++){if(i%3==0)continue;Console.WriteLine("{0}\t",i);}}

2023/2/461C#程序设计实用教程

5.4.1方法的定义及调用

staticvoidMain(){MyClassmycls=newMyClass();mycls.myMethod();}}}程序的运行结果为:1245782023/2/462C#程序设计实用教程

5.4.1方法的定义及调用

【例5-12】通过方法的return语句返回。usingSystem;

namespaceMethod{classMyClass{publicvoidmyMethod(){inti=8;if(i>=5){i=i*2;Console.WriteLine(i);return;}else{i=i*3;Console.WriteLine(i);return;}}staticvoidMain(){MyClassmycls=newMyClass();mycls.myMethod();}}}2023/2/463C#程序设计实用教程

5.4.1方法的定义及调用

使用下述形式的return语句从方法返回一个值给调用者:格式:returnvalue;【例5-13】通过方法的return语句返回值。usingSystem;

namespaceMethod{classMyClass{publicintmyMethod(){inti=8;if(i>=5){i=i*2;returni;}

else{i=i*3;returni;}}staticvoidMain(){MyClassmycls=newMyClass();Console.WriteLine(mycls.myMethod());}}}2023/2/464C#程序设计实用教程

5.4.2方法的参数

调用方法时,可以给方法传递一个或多个值。传给方法的值称为实参(argument),在方法内部,接收实参值的变量称为形参(parameter),形参在紧跟着方法名的括号中声明。形参的声明语法与变量的声明语法一样。形参只在方法内部有效,除了将接收实参的值外,它与一般的变量没什么区别。C#方法的参数类型主要有:值参数、引用参数、输出参数和参数数组。2023/2/465C#程序设计实用教程

5.4.2方法的参数

1.值参数没有用任何修饰符声明的参数为值参数,它表明实参与形参之间按值传递。当这个方法被调用时,编译器为值参数分配存储单元,然后将对应的实参的值拷贝到形参中。实参可以是变量、常量、表达式,但要求其值的类型必须与形参声明的类型相同或者能够被隐式地转化为这种类型。这种传递方式的好处是在方法中对形参的修改不会影响外部的实参,也就是说数据只能传入方法而不能从方法传出。2023/2/466C#程序设计实用教程

5.4.2方法的参数

【例5-14】使用值参数。usingSystem;

namespaceValueParameters{classMyClass{publicvoidSwap(intx,inty){intk;k=x;x=y;y=k;}}

2023/2/467C#程序设计实用教程

5.4.2方法的参数

classTest{staticvoidMain(){inta=8,b=10;Console.WriteLine("a={0},b={1}",a,b);MyClassmycls=newMyClass();mycls.Swap(a,b);Console.WriteLine("a={0},b={1}",a,b);}}}程序的运行结果为:a=8,b=10a=8,b=102023/2/468C#程序设计实用教程

5.4.2方法的参数

2.引用参数用ref修饰符声明的参数为引用参数。引用参数与值参数不同,引用参数并不创建新存储单元,它与方法调用中的实参变量同处一个存储单元。因此,在方法内对形参的修改就是对外部实参变量的修改。在函数调用中,引用参数必须被赋初值。在调用时,传递给ref参数的必须是变量,类型必须相同,并且必须使用ref修饰。2023/2/469C#程序设计实用教程

5.4.2方法的参数

【例5-15】使用引用参数。usingSystem;

namespaceReferenceParameters{classMyClass{publicvoidSwap(refintx,refinty){intk;k=x;x=y;y=k;}}2023/2/470C#程序设计实用教程

5.4.2方法的参数

classTest{staticvoidMain(){inta=8,b=10;Console.WriteLine("a={0},b={1}",a,b);MyClassmycls=newMyClass();mycls.Swap(refa,refb);Console.WriteLine("a={0},b={1}",a,b);}}}程序的运行结果为:a=8,b=10a=10,b=82023/2/471C#程序设计实用教程

5.4.2方法的参数

3.输出参数用out修饰符定义的参数称为输出参数。如果希望方法返回多个值,可使用输出参数。输出参数与引用参数类似,它也不产生新的存储空间。两者的区别在于:out参数只能用于从方法中传出值,而不能从方法调用处接受实参数值;在方法体内out参数被认为是未赋过值的,所以在方法结束之前应该对out参数赋值。2023/2/472C#程序设计实用教程

5.4.2方法的参数

【例5-16】使用输出参数。usingSystem;

namespaceOutputParameters{publicclassStudent{publicstringstrName;//姓名publicintnAge;//年龄

///构造函数publicStudent(string_strName,int_nAge){strName=_strName;nAge=_nAge;}

2023/2/473C#程序设计实用教程

5.4.2方法的参数

///长大_nSpan岁publicvoidGrow(int_nSpan,outint_nOutCurrentAge){nAge+=_nSpan;_nOutCurrentAge=nAge;}}publicclassTest{staticvoidMain(){Students=newStudent("张三",21);intnCurrentAge;s.Grow(3,outnCurrentAge);Console.WriteLine(s.nAge);//输出24}}}2023/2/474C#程序设计实用教程

5.4.2方法的参数

程序的输出结果如下:24注意:在上例中,在调用时需要在输入参数前加out关键字。2023/2/475C#程序设计实用教程

5.4.2方法的参数

4.参数数组有时候,在调用一个方法时,预先不能确定参数的数量、数据类型等,怎么办呢?一种解决方案是使用params关键字。params关键字指明一个输入参数,此输入参数将被看作为一个参数数组,这种类型的输入参数只能作为方法的最后一个参数。以下例说明其功能。2023/2/476C#程序设计实用教程

5.4.2方法的参数

【例5-17】使用参数数组。usingSystem;

namespaceParameterArray{publicclassStudent{publicstringstrName; //姓名publicintnAge; //年龄publicSystem.Collections.ArrayListstrArrHobby=newSystem.Collections.ArrayList(); //爱好

2023/2/477C#程序设计实用教程

5.4.2方法的参数

///<summary>///构造函数///</summary>publicStudent(string_strName,int_nAge){this.strName=_strName;this.nAge=_nAge;}

///<summary>///为爱好赋值///</summary>publicvoidSetHobby(paramsstring[]_strArrHobby){for(inti=0;i<_strArrHobby.Length;i++)this.strArrHobby.Add(_strArrHobby[i]);}}

2023/2/478C#程序设计实用教程

5.4.2方法的参数

classTest{staticvoidMain(string[]args){Students=newStudent("张三",20);

s.SetHobby("游泳","篮球","足球");

for(inti=0;i<s.strArrHobby.Count;i++)Console.WriteLine(s.strArrHobby[i]);}}}2023/2/479C#程序设计实用教程

5.4.2方法的参数

程序的输出结果如下:

游泳

篮球

足球注意:上例为Student类实现了一个爱好赋值方法,用于确定学生的爱好。因为实现无法确定学生的爱好数目,因此可以使用params参数来接收多个字符串参数,并整体作为数组传递给方法。2023/2/480C#程序设计实用教程

5.4.3方法的重载

有时,对于类需要完成的同一个功能,要求可能比较复杂。例如,对学生类而言,如果想要使其具有一个“成长”方法,但是这个方法,可能是使学生增加一岁,也可能是增加指定的岁数,该如何解决这个问题呢?C#使用重载技术来完成这个功能。重载是指允许存在多个同名函数,而这函数的参数不同(或许是参数个数不同,或许参数类型不同,或许两者都不同)。在调用这个方法时,编译器可以按照输入的参数去调用适当的方法。下例所示代码完成本节所提出的学生“成长”问题。2023/2/481C#程序设计实用教程

5.4.3方法的重载

【例5-18】方法的重载。usingSystem;

namespaceMethodOverload{///<summary>///学生类///</summary>publicclassStudent{//属性

publicstringstrName; //姓名publicintnAge; //年龄

2023/2/482C#程序设计实用教程

5.4.3方法的重载

///<summary>///成长1岁///</summary>publicvoidGrow(){this.nAge++;}

///<summary>///成长_nAgeSpan岁///</summary>publicvoidGrow(int_nAgeSpan){this.nAge+=_nAgeSpan;}}

2023/2/483C#程序设计实用教程

5.4.3方法的重载

///<summary>///Main函数类///</summary>classClass1{staticvoidMain(string[]args){Students=newStudent();s.strName="张三";s.nAge=20;s.Grow();Console.WriteLine(s.nAge); //输出21s.Grow(2);Console.WriteLine(s.nAge); //输出23}}}2023/2/484C#程序设计实用教程

5.4.3方法的重载

程序运行如果如下: 21 23注意:在示例中,定义了学生类,在类中实现了两个Grow()方法;前一个Grow()方法,没有任何输入参数,其功能为使学生年龄加1,后一个同名方法Grow(),带有一个参数_nAgeSpan,其功能为使学生年龄加nAgeSpan。在主函数中,分别调用学生类的Grow()方法,并输入不同的参数,从而得到不同的结果。这样,就可以使用同样的方法名,完成功能类似、具体实现不同的任务了。2023/2/485C#程序设计实用教程

5.4.4静态方法和非静态方法

使用static修饰符的方法称为静态方法,没有使用static修饰符的方法称为非静态方法。静态方法和非静态方法的区别是:静态方法表示类所具有的行为,而非其某个具体对象所具有的行为。例如学生分班这项任务,就是全体学生集体的事情,而非某个学生的事情。静态方法的访问级别关键字同普通方法一样,但是很少是private,因为一般需要在类的外部访问类的静态方法。在调用静态方法时不需要实例化类的对象。直接使用类引用即可。2023/2/486C#程序设计实用教程

5.4.4静态方法和非静态方法

【例5-19】使用静态方法和非静态方法。usingSystem;

namespaceStaticMethod{classMyClass{publicinta;staticpublicintb;voidFun1()//定义一个非静态方法{a=10;

//正确,直接访问非静态方法b=20;

//正确,直接访问静态方法}2023/2/487C#程序设计实用教程

5.4.4静态方法和非静态方法

staticvoidFun2()

//定义一个静态方法{a=10;

//错误,不能访问非静态方法b=20;

//正确,可以访问静态成员,相当于MyClass.b=20}}classTest{staticvoidMain(){MyClassclsA=newMyClass();clsA.a=10;

//正确,访问类MyClass的非静态公有成员clsA.b=20;

//错误,不能直接访问类中静态公有成员2023/2/488C#程序设计实用教程

5.4.4静态方法和非静态方法

MyClass.a=30;

//错误,不能通过类名访问类中非静态公有成员MyClass.b=40;

//正确,访问类MyClass中静态公有成员}}}2023/2/489C#程序设计实用教程

5.4.5运算符的重载

运算符也是C#类的一个成员,系统对大部分运算符都给出了常规定义,这些定义大部分和现实生活中这些运算符的意义相同。在实际应用中,有些数据、结构或类之间是没有运算可言的,例如对一个姓名进行++操作是没有意义的。但如果把一个班的全体学生的姓名存成一个数据库,用string类型的变量name来存储其中某个学生的姓名,那么编程人员总想进行name++操作来获取下一个学生的姓名,这时就可以对++运算符进行重载。在C#中,运算符重载在类中进行声明,并且通过调用类的成员方法来实现。2023/2/490C#程序设计实用教程

5.4.5运算符的重载

运算符重载声明的格式为:返回类型operator重载的运算符(运算符参数列表){运算符重载的实现部分}和方法声明一样,返回类型可以根据函数实际需要设定为任意合法的C#类型修饰符。在方法实现部分通过return语句返回该数据类型。在C#中,可以重载的运算符主要有: +-!~

++--truefalse*/%|&^<<>>==<><=>=不能重载的运算符有: =&&||?:newtypeofsizeofis2023/2/491C#程序设计实用教程

5.4.5运算符的重载

【例5-20】假设空间的某一点的坐标为(x,y,z),规定为~(x,y,z)关于原点的对称。要实现这一功能,需要对一元运算符“~”进行重载。程序代码如下:usingSystem;namespaceOperatorReload{classSpace{publicintx,y,z;publicSpace(intxx,intyy,intzz){x=xx;y=yy;z=zz;}2023/2/492C#程序设计实用教程

5.4.5运算符的重载

publicstaticSpaceoperator~(Spaced1){SpaceNeg=newSpace(0,0,0);Neg.x=(-1)*d1.x;Neg.y=(-1)*d1.y;Neg.z=(-1)*d1.z;returnNeg;}}

2023/2/493C#程序设计实用教程

5.4.5运算符的重载

classTest{publicstaticvoidMain(){Spaced1=newSpace(1,2,3);Spaced2=~d1;Console.WriteLine("空间坐标(1,2,3)的关于对称坐标是:({0},{1},{2})。",d2.x,d2.y,d2.z);Console.Read();}}}程序运行如果如下:

空间坐标(1,2,3)的关于对称坐标是:(-1,-2,-3)。2023/2/494C#程序设计实用教程

5.5属性

在前面简单介绍了类的静态属性,本节将对其做更深入的探讨。2023/2/495C#程序设计实用教程

5.5.1字段和属性

如果想把类的静态特征分得更细,可以把其分为字段和属性两类。1、字段(Field)又称为域,表示存储位置。2、属性(Attribute)在编程思想上真正实现了面向对象对“属性”的准确定义,不表示存储位置,而是一个特殊的接口,用于对外交互类的静态信息。具有两个函数:取值函数get(),获取字段的值;赋值函数set(),为字段赋值,使用value关键字获取用户输入。2023/2/496C#程序设计实用教程

5.5.1

温馨提示

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

评论

0/150

提交评论