C#程序设计第6章 类的属性和方法.docx
- 文档编号:13595215
- 上传时间:2023-06-15
- 格式:DOCX
- 页数:53
- 大小:46.15KB
C#程序设计第6章 类的属性和方法.docx
《C#程序设计第6章 类的属性和方法.docx》由会员分享,可在线阅读,更多相关《C#程序设计第6章 类的属性和方法.docx(53页珍藏版)》请在冰点文库上搜索。
C#程序设计第6章类的属性和方法
第6章面向对象编程基础
6.1面向对象编程概念
在面向对象程序设计技术中,对象是具有属性和操作(方法)的实体。
对象的属性表示了它所处的状态;对象的操作则用来改变对象的状态达到特定的功能。
对象有一个唯一的标识名以区别于其他对象,对象有固定的对外接口,它是对象与外界通信的通道。
类是在对象之上的抽象,它为属于该类的全部对象提供了统一的抽象描述。
所以类是一种抽象的数据类型,它是对象的模板,对象则是类的具体化,是类的实例。
面向对象程序设计在处理对象时,必须遵循的三个原则是:
封装、继承、多态。
1.封装
所谓“封装”,就是用一个框架把数据和代码组合在一起,形成一个对象。
在C#中,类是支持对象封装的工具,对象则是封装的基本单元。
2.继承
继承是面向对象程序设计的一块基石,通过它可以创建分等级层次的类。
继承是父类和子类之间共享数据和方法的机制,通常把父类称为基类,子类称为派生类。
一个基类可以有任意数目的派生类
如果一个类有两个或两个以上的直接基类,这样的继承结构被称为多重继承或多继承。
C#通过接口来实现多重继承。
接口可以从多个基接口继承。
3.多态性
在面向对象编程中,多态是指同一个操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
多态性有两种,一种是静态多态,一种是动态多态。
6.2类
对象是面向对象语言的核心,数据抽象和对象封装是面向对象技术的基本要求,而实现这一切的主要手段和工具就是类。
类就是一种数据结构,它定义数据和操作这些数据的代码。
6.2.1类的声明
要定义一个新的类,首先要声明它。
语法形式:
[属性集信息][类修饰符]class类名[:
类基]
{
[类主体]
}
其中:
属性集信息——是C#语言提供给程序员的,为程序中定义的各种实体附加一些说明信息,这是C#语言的一个重要特征。
类修饰符——可以是表3.1所列的几种之一或是它们的有效组合,但在类声明中,同一修饰符不允许出现多次。
表6.1类修饰符
修饰符
作用说明
public
表示不限制对类的访问。
类的访问权限省略时默认为public
protected
表示该类只能被这个类的成员或派生类成员访问
private
表示该类只能被这个类的成员访问
internal
表示该类能够由程序集中的所有文件使用,而不能由程序集之外的对象使用
New
只允许用在嵌套类中,它表示所修饰的类会隐藏继承下来的同名成员
abstract
表示这是一个抽象类,该类含有抽象成员,因此不能被实例化,只能用作基类
sealed
表示这是一个密封类,不能从这个类再派生出其他类。
显然密封类不能同时为抽象类
6.2.2类的成员
类的定义包括类头和类体两部分,其中类体用一对大花括号{}括起来,类体用于定义该类的成员。
语法形式:
{
[类成员声明]
}
类成员由两部分组成,一个是类体中以类成员声明形式引入的类成员,另一个则是直接从它的基类继承而来的成员。
类成员声明主要包括:
常数声明、字段声明、方法声明、属性声明、事件声明、索引器声明、运算符声明、构造函数声明、析构函数声明、静态构造函数、类型声明等。
1.常数声明
语法形式:
[属性集信息][常数修饰符]const类型标识符=常数表达式[,…]
其中:
●常数修饰符——new、public、protected、internal、private。
●类型——sbyte、byte、short、ushort、int、uint、long、ulong、char、float、double、decimal、bool、string、枚举类型或引用类型。
常数表达式的值类型应与目标类型一致,或者通过隐式转换规则转换成目标类型。
例如:
classA_const
{
publicconstintX=10;
constdoublePI=3.14159;//默认访问修饰符,即约定为private
constdoubleY=0.618+3.14;
}
常数表达式的值应该是一个可以在编译时计算的值,常数声明不允许使用static修饰符,但它和静态成员一样只能通过类访问。
例如:
classTest
{
publicstaticvoidMain()
{
A_constm=newA_const();
Console.WriteLine("X={0},PI={1},Y={2}",A_const.X,A_const.PIA_const.Y);
}
}
2.字段声明
语法形式:
[属性集信息][字段修饰符]类型变量声明列表;
其中:
⏹变量声明列表——标识符或用逗号“,”分隔的多个标识符,并且变量标识符还可用赋值号“=”设定初始值。
例如:
classA
{
intx=100,y=200;
floatsum=1.0f;
}
⏹字段修饰符——new、public、protected、internal、private、static、readonly、volatile。
【例6.1】通过构造函数给只读字段赋值
usingSystem;
publicclassArea
{
publicreadonlydoubleRadius;//Radius是只读字段
privatedoublex,y;
publicdoubleSize;
publicstaticdoubleSum=0.0;
publicArea()
{
Radius=1.0;//通过构造函数对radius赋值
}
}
classTest
{
publicstaticvoidMain()
{
Areas1=newArea();
Console.WriteLine("Radius={0},Size={1},Sum={2}",s1.Radius,s1.Size,Area.Sum);
//静态字段通过类访问Area.Sum,实例字段通过对象访问s1.Size
Console.Read();
}
}
程序运行结果如下:
无论是静态字段还是实例字段,它们的初始值都被设置成字段类型的默认值。
如果字段声明包含变量初始值设定,则在初始化执行期间相当于执行一个赋值语句。
对静态字段的初始化发生在第一次使用该类静态字段之前,执行的顺序按静态字段在类声明中出现的文本顺序进行。
当实例字段的初始化发生在创建一个类的实例时,同样是按实例字段在类声明中的文本顺序执行的。
6.2.3构造函数和析构函数
1.构造函数
为了能规范、安全地使用这个对象,C#提供了实现对象进行初始化的方法,这就是构造函数。
在C#中,类的成员字段可以分为实例字段和静态字段,与此相应的构造函数也分为实例构造函数和静态构造函数。
(1)实例构造函数的声明
语法形式:
[属性集信息][构造函数修饰符]标识符([参数列表])
[:
base([参数列表])][:
this([参数列表])]
{
构造函数语句块
}
●构造函数修饰符——public、protected、internal、private、extern。
一般地,构造函数总是public类型的。
如果是private类型的,表明类不能被外部类实例化。
●标识符([参数列表]opt)——构造函数名,必须与这个类同名,不声明返回类型,并且没有任何返回值。
它与返回值类型为void的函数不同。
构造函数可以没有参数,也可以有一个或多个。
这表明构造函数在类的声明中可以有函数名相同,但参数个数不同或者参数类型不同的多种形式,这就是所谓的构造函数重载。
用new运算符创建一个类的对象时,类名后的一对圆括号提供初始化列表,这实际上就是提供给构造函数的参数。
系统根据这个初始化列表的参数个数、参数类型和参数顺序调用不同的构造函数。
【例6.2】Time类的构造函数及其重载。
usingSystem;
publicclassTime
{
privateinthour,minute,second;
publicTime()
{
hour=minute=second=0;
}
publicTime(inth)
{
hour=h;
minute=second=0;
}
publicTime(inth,intm)
{
hour=h;
minute=m;
second=0;
}
publicTime(inth,intm,ints)
{
hour=h;
minute=m;
second=s;
}
}
classTest
{
staticvoidMain()
{
Timet1,t2,t3,t4;//对t1,t2,t3,t4分别调用不同的构造函数
t1=newTime();
t2=newTime(8);
t3=newTime(8,30);
t4=newTime(8,30,30);
}
}
【例6.3】构造函数初始化。
实例对象创建时,根据不同的参数调用相应的构造函数完成初始化。
usingSystem;
classPoint
{
publicdoublex,y;
publicPoint()
{
x=0; y=0;
}
publicPoint(doublex,doubley)
{
this.x=x;//当this在实例构造函数中使用时,
this.y=y;//它的值就是对该构造的对象的引用
}
}
classTest
{
publicstaticvoidMain()
{
Pointa=newPoint();
Pointb=newPoint(3,4);//用构造函数初始化对象
Console.WriteLine("a.x={0},a.y={1}",a.x,a.y);//a.x=0,a.y=0
Console.WriteLine("b.x={0},b.y={1}",b.x,b.y);//b.x=3,b.y=4
Console.Read();
}
}
上例中声明了一个类Point,它提供了两个重载的构造函数。
一个是不带参数的Point构造函数和一个是带有两个double参数的Point构造函数。
如果类中没有提供这些构造函数,那么CLR会自动提供一个默认的构造函数。
一旦类中提供了自定义的构造函数,系统则不提供默认的构造函数,这一点需要特别注意,否则系统编译会报出错。
下面程序描述了派生类构造函数的格式,以及在初始化对象时构造函数的调用次序。
【例6.4】派生类构造函数及其调用。
usingSystem;
classPoint
{
privateintx,y;
publicPoint()
{
x=0; y=0;
Console.WriteLine("Point()constructor:
{0}",this);
}
publicPoint(intx,inty)
{
this.x=x;
this.y=y;
Console.WriteLine("Point(x,y)constructor:
{0}",this);
}
}
classCircle:
Point
{
privatedoubleradius;
publicCircle()//默认约定调用基类的无参构造函数Point()
{
Console.WriteLine("Circle()constructor:
{0}",this);
}
publicCircle(doubleradius):
base()
{
this.radius=radius;
Console.WriteLine("Circle(radius)constructor:
{0}",this);
}
publicCircle(intx,inty,doubleradius):
base(x,y)
{
this.radius=radius;
Console.WriteLine("Circle(x,y,radius)constructor:
{0}",this);
}
}
classTest
{
staticvoidMain()
{
Pointa=newPoint();
Circleb=newCircle(3.5);
Circlec=newCircle(1,1,4.8);
Console.Read(); }}
程序运行结果如下:
(2)静态构造函数的声明
语法形式:
[属性集信息][静态构造函数修饰符]标识符()
{
静态构造函数体
}
其中:
●静态构造函数修饰符——[extern]static或者static[extern]。
如果有extern修饰,则说明这是一个外部静态构造函数,不提供任何实际的实现,所以静态构造函数体仅仅是一个分号。
●标识符()——是静态构造函数名,必须与这个类同名,静态构造函数不能有参数。
●静态构造函数体——静态构造函数的目的是对静态字段的初始化,所以它只能对静态数据成员进行初始化,而不能对非静态数据成员进行初始化。
关于构造函数,还有几点请注意:
●:
base([参数列表]opt)——表示调用直接基类中的实例构造函数。
●:
this([参数列表]opt)——表示调用该类本身所声明的其他构造函数。
●构造函数语句块——既可以对静态字段赋值,也可以对非静态字段进行初始化。
但在构造函数体中不要做对类的实例进行初始化以外的事情,也不要尝试显式地调用构造函数。
●实例构造函数——不能被继承。
如果一个类没有声明任何实例构造函数,则系统会自动提供一个默认的实例构造函数
【例6.5】静态构造函数。
usingSystem;
classScreen
{
staticintHeight;
staticintWidth;
intCur_X,Cur_Y;
staticScreen()
{//静态构造函数,对类的静态字段初始化
Height=768;
Width=1024;
}
}
关于静态构造函数,请注意:
●静态构造函数是不可继承的,而且不能被直接调用。
●只有创建类的实例或者引用类的任何静态成员时,才能激活静态构造函数,所以在给定的应用程序域中静态构造函数至多被执行一次。
●如果类中没有声明静态构造函数,而又包含带有初始设定的静态字段,那么编译器会自动生成一个默认的静态构造函数。
2.析构函数
语法形式:
[属性集信息][extern]~标识符()
{
析构函数体
}
其中:
●标识符——必须与类名相同,但为了区分构造函数,前面需加“~”,表明它是析构函数。
关于析构函数,请注意:
析构函数不能由程序显式地调用,而是由系统在释放对象时自动调用。
如果对象是一个派生类对象,那么在调用析构函数时也会产生链式反应,首先执行派生类的析构函数,然后执行基类的析构函数,如果这个基类还有自己的基类,这个过程就会不断重复,直到调用Object类的析构函数为止,其执行顺序正好与构造函数相反。
●析构函数——不能写返回类型,也不能带参数,因此它不可能被重载,当然它也不能被继承,所以一个类最多只能有一个析构函数。
关于析构函数,请注意:
析构函数不能由程序显式地调用,而是由系统在释放对象时自动调用。
如果对象是一个派生类对象,那么在调用析构函数时也会产生链式反应,首先执行派生类的析构函数,然后执行基类的析构函数,如果这个基类还有自己的基类,这个过程就会不断重复,直到调用Object类的析构函数为止,其执行顺序正好与构造函数相反。
6.3方法
C#实现了完全意义上的面向对象,它没有全局常数、全局变量和全局方法,任何事物都必须封装在类中。
通常,程序的其他部分通过类所提供的方法与它进行互操作。
对方法的理解可以从方法的声明、方法的参数、静态方法与实例方法、方法的重载与覆盖等方面切入。
6.3.1方法的声明
方法是按照一定格式组织的一段程序代码,在类中用方法声明的方式来定义。
语法形式:
[属性集信息][方法修饰符]返回类型方法名([形参表])
{
方法体
}
表6.2方法修饰符
修饰符
作用说明
New
在一个继承结构中,用于隐藏基类同名的方法
public
表示该方法可以在任何地方被访问
protected
表示该方法可以在它的类体或派生类类体中被访问,但不能在类体外访问
private
表示该方法只能在这个类体内被访问
internal
表示该方法可以被同处于一个工程的文件访问
static
表示该方法属于类型本身,而不属于某特定对象
virtual
表示该方法可在派生类中重写,来更改该方法的实现
abstract
表示该方法仅仅定义了方法名及执行方式,但没有给出具体实现,所以包含这种方法的类是抽象类,有待于派生类的实现
override
表示该方法是将从基类继承的virtual方法的新实现
sealed
表示这是一个密封方法,它必须同时包含override修饰,以防止它的派生类进一步重写该方法
extern
表示该方法从外部实现
方法修饰符中public、protected、private、internal、protectedinternal属于访问修饰符,表示访问的级别,默认情况下,方法的访问级别为public。
访问修饰符也可以和其他的方法修饰符有效地组合在一起,但某些修饰符是互相排斥的。
表3.3所列的组合被视为非法的无效组合。
1.返回类型——方法可以返回值也可以不返回值。
如果返回值,则需要说明返回值的类型,它可以是任何一种C#的数据类型,在方法体内通过return语句将数据交给调用者。
如果方法不返回值,则它的返回类型可标为void,默认情况下为void。
表6.3修饰符的无效组合
修饰符
不能与下列选项一起使用
static
virtual、abstract和override
virtual
static、abstract和override
override
new、static和virtual
abstract
virtual和static
New
Override
extern
Abstract
●方法名——每个方法都有一个名称,一般可以按标识符的起名规则随意给定方法名,不过要记住Main()是为开始执行程序的方法预留的,另外不要使用C#的关键字作为方法名。
为了使方法容易理解和记忆,建议方法的命名尽可能地同所要进行的操作联系起来,就是我们通常说的顾名思义。
●形参表——由零个或多个用逗号分隔的形式参数组成,形式参数可用属性、参数修饰符、类型等描述。
当形参表为空时,外面的圆括号也不能省略。
●方法体——用花括号括起的一个语句块。
【例6.6】下面程序中的StackTp类定义了几个方法以模拟实现一个压栈操作。
构造函数的声明
usingSystem;
classStackTp
{
intMaxSize;
intTop;
int[]StkList;
publicStackTp()//构造函数
{
MaxSize=100;
Top=0;
StkList=newint[MaxSize];
}
publicStackTp(intsize)//构造函数
{
MaxSize=size;
Top=0;
StkList=newint[MaxSize];
}
publicboolisEmptyStack()//方法
{
if(Top==0)
returntrue;
else
returnfalse;
}
publicboolisFullStack()
{
if(Top==MaxSize)
returntrue;
else
returnfalse;
}
publicvoidpush(intx)
{
StkList[Top]=x;
Top++;
}
}
classTest
{
publicstaticvoidMain()
{
StackTpST=newStackTp(20);
strings1;
if(ST.isEmptyStack())//调用方法isEmptyStack()
s1="Empty";
else
s1="notEmpty";
Console.WriteLine("Stackis"+s1);
for(inti=0;i<20;i++)
ST.push(i+1);
if(ST.isFullStack())//调用方法isFullStack()
s1="Full";
else
s1="notFull";
Console.WriteLine("Stackis"+s1);
Console.Read();
}
}
程序运行结果如下:
6.3.2方法的参数
参数的传入或传出就是在实参与形参之间发生的,
在C#中实参与形参有4种传递方式。
1.值参数
在方法声明时不加修饰的形参就是值参数,它表明实参与形参之间按值传递。
这种传递方式的好处是,在方法中对形参的修改不影响外部的实参,也就是说,数据只能传入方法而不能从方法传出,所以值参数有时也被称为入参数。
【例6.7】下面的程序演示了当方法Sort传递的是值参数时,对形参的修改不影响其实参。
usingSystem;
classMyclass
{
publicvoidSort(intx,inty,intz)
{
inttmp;//tmp是方法Sort的局部变量
//将x,y,z按从小到大排序
if(x>y){tmp=x;x=y;y=tmp;}
if(x>z){tmp=x;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- C#程序设计第6章 类的属性和方法 C# 程序设计 属性 方法