C#程序设计第3章.docx

上传人:b****5 文档编号:6649254 上传时间:2023-01-08 格式:DOCX 页数:53 大小:32.96KB
下载 相关 举报
C#程序设计第3章.docx_第1页
第1页 / 共53页
C#程序设计第3章.docx_第2页
第2页 / 共53页
C#程序设计第3章.docx_第3页
第3页 / 共53页
C#程序设计第3章.docx_第4页
第4页 / 共53页
C#程序设计第3章.docx_第5页
第5页 / 共53页
点击查看更多>>
下载资源
资源描述

C#程序设计第3章.docx

《C#程序设计第3章.docx》由会员分享,可在线阅读,更多相关《C#程序设计第3章.docx(53页珍藏版)》请在冰豆网上搜索。

C#程序设计第3章.docx

C#程序设计第3章

第3章面向对象编程

3.1概述

⏹面向过程的程序设计(POP,Procedure-OrientedProgramming)

◆包含一个主过程和若干个子过程;

◆代码和数据是分离的,程序的可维护性差;

◆面向过程的程序设计语言:

C、Pascal、Fortran、Basic。

⏹面向对象的程序设计(OOP,Object-OrientedProgramming)

◆将数据及处理这些数据的操作都封装(Encapsulation)到一个称为类(Class)的数据结构中。

◆使用这个类时,只需要定义一个类的变量即可,这个变量叫做对象(Object)。

◆封装性(类)、继承性、多态性。

◆优点:

程序可维护性好;程序易于修改;对象可以使用多次,即可重用性好。

3.2类

类:

是面向对象编程的基本构造块,是一种包含数据成员、函数成员、嵌套类型的数据结构。

⏹数据成员:

常量、域(field)、事件

⏹函数成员:

包含可执行代码的成员,包括方法、属性、操作符、索引指示器(indexer)、构造函数、析构函数。

3.2.1类的声明

类的声明的格式:

[类修饰符]class类名[:

基类类名]

{

类的成员;

};

⏹类修饰符:

◆new:

新建类,表明由基类中继承而来的、与基类中同名的成员。

◆public:

公有类,表示外界可以不受限制地访问。

◆protected:

保护类,表示可以访问该类或从该类派生的类型。

◆internal:

内部类,表明仅能访问本程序。

◆private:

私有类,表明只有该类才能访问。

◆abstract:

抽象类,说明该类是一个不完整的类,只有声明而没有具体的实现。

一般只能用做其它类的基类,不能单独使用。

◆sealed:

密封类,说明该类不能作其它类的基类,不能再派生新的类。

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

(1)在一个类声明中,同一类修饰符不能出现多次。

(2)new类修饰符仅允许在嵌套类中表示类声明时使用,表明类中隐藏了由基类中继承而来的、与基类中同名的成员。

(3)在使用public、protected、internal、private这些类修饰符时,要注意这些类修饰符不仅表示所定义类的访问特性,而且还表明类中成员声明时的访问特性,并且它们的可用性也会对派生类造成影响。

(4)抽象类修饰符abstract和密封类修饰符sealed都是受限类修饰符。

◆抽象类只能作其它类的基类,不能建立抽象类的实例,即对抽象类使用new操作符是错误的。

◆密封类不能作其它类的基类,可以由其它类继承而来但不能再派生其它类。

◆一个类不能同时使用抽象类修饰符和密封类修饰符。

(5)如果省略类修饰符,则默认为私有修饰符private。

(6)对于具有继承关系的类才有基类。

◆如果一个类没有从任何类继承,就不需要基类类名选项。

◆在C#中,只允许单继承,不允许多继承。

◆如果一个类想继承多个类的特点,可以采用接口的方法实现。

3.2.2类的成员

(1)类的成员:

按照类的成员是否为函数,分为以下类型:

⏹成员变量(不以函数形式出现)

◆常量:

代表与类相关的常量值。

◆变量:

类中的变量,相当于C++中的成员变量。

◆事件:

由类产生的通知,用于说明发生了什么事情。

◆类型:

属于类的局部类型。

⏹成员函数(以函数形式出现)

◆方法:

完成类中各种计算或功能的操作。

◆属性:

定义类的值,并对它们提供读、写操作。

◆索引器:

允许编程人员在访问数组时,通过索引器访问类的多个实例。

又称下标指示器。

◆运算符:

定义类的实例能使用的运算符。

◆构造函数:

在类被实例化时首先执行的函数,主要是完成对象初始化操作。

◆析构函数:

在对象被销毁之前最后执行的函数,主要完成对象结束时的收尾操作。

(2)类的成员:

按照类的成员设定的访问修饰符,分为以下类型:

⏹公有成员:

public,允许类的内部或外界直接访问。

⏹私有成员:

private,外界不能直接访问该成员变量或成员函数。

⏹保护成员:

protected,对于外界该成员是隐藏的,但这个类的派生类可以访问。

⏹内部成员:

internal,这种成员对同一包中的应用程序或库是透明的,但在包之外是禁止访问的。

//ch3_1.cs

usingSystem;

classClass1

{

publicstrings;//公有成员

protectedinti;//保护成员

privatedoubled;//私有成员

publicvoidF1()

{

s="Welcometoyou!

";//正确,允许访问自身成员

i=1000;//正确,允许访问自身成员

d=168.68;//正确,允许访问自身成员

}

}

classClass2:

Class1//从Class1派生类Class2

{

intx;//私有成员

publicvoidF2()

{

x=2000;//正确,允许访问自身成员

s="Hello";//正确,允许访问类Class1的公有成员

d=188.88;//错误,不能访问类Class1的私有成员

i=3000;//正确,允许访问类Class1的保护成员

}

}

classClass3

{

publicvoidF3()

{

Class1c=newClass1();//声明类Class1的实例C

c.s="Welcome";//正确,允许访问类Class1的公有成员

c.d=209.99;//错误,不能访问类Class1的保护成员

c.i=5000;//错误,不能访问类Class1的私有成员

}

}

3.2.3this关键字

this关键字只能在类的构造函数、类的方法和类的实例中使用,它的含义是:

⏹在类的构造函数中出现的this表示对正在构造的对象本身的引用。

⏹在类的方法中出现的this表示对调用该方法的对象的引用

⏹在结构的构造函数中出现的this表示对正在构造的结构的引用

⏹在结构的方法中出现的this表示对该方法的结构的引用。

//ch3_2.cs

usingSystem;

publicclassEmployee

{

publicstringname;//员工姓名

publicdecimalsalary;//员工薪水

//构造函数

publicEmployee(stringname,decimalsalary)

{

//用this关键字给正在构造的对象的name和salary赋值

this.name=name;

this.salary=salary;

}

//显示员工姓名及薪水

publicvoidDiaplayEmployee()

{

Console.WriteLine("姓名:

{0}",name);

Console.WriteLine("薪水:

{0}元",salary);

//用this方法将当前对象传给Tax.CalcTax()方法

Console.WriteLine("个人所得税:

{0}元",Tax.CalcTax(this));

}

}

publicclassTax

{

//CalcTax()方法计算个人所得税

publicstaticdecimalCalcTax(EmployeeE)

{

return(0.14m*(E.salary-800.0m));

}

}

publicclassSample

{

publicstaticvoidMain()

{

//声明类Employee的实例e

Employeee=newEmployee("木林森",3168.0m);

e.DiaplayEmployee();//显示员工姓名和薪水

}

}

程序输出结果:

姓名:

木林森

薪水:

3168元

个人所得税:

331.52元

3.2.4静态成员和非静态成员

类的静态成员:

用static声明,属于类所有,不必产生类的实例就可访问它,为类的所有实例所共享。

类的非静态成员:

属于类的实例所有,每创建一个类的实例,都在内存中为非静态成员开辟了一块区域。

//ch3_3.cs

usingSystem;

classEmployee{

publicstaticdecimalSalary;//静态成员

publicstringName;//非静态成员

publicstaticvoidSetSalary(decimalB)

{

Salary=B;//正确,等价于Employee.Salary=B

}

publicvoidSetName(stringN)

{

Name=N;//正确,等价于this.Name=N

}

}

classSample

{

publicstaticvoidMain()

{

Employee.Salary=6000.0m;//正确,静态成员可以按类名访问

Employee.SetSalary(6000.0m);//正确,静态成员可以按类名访问

Employeee=newEmployee();//建立类Employee的一个实例

e.Name="高越明";//正确,非静态成员必须通过实例访问

e.SetName("高越明");//正确,非静态成员必须通过实例访问

//注意,e.Name不能写成Employee.Name,即非静态成员不能按类名访问

//Employee.Salary也不能写成e.Salary,即静态成员不能通过类的实例访问

e.WriteLine("员工姓名:

{0}\n薪水:

{1}元",e.Name,Employee.Salary);

}

}

 

程序输出结果:

员工姓名:

高越明

薪水:

6000元

3.2.5成员常量

成员常量:

表示与类相关联的常量值。

//ch3_4.cs

usingSystem;

classCircle{

publicconstdoublePI=3.1415926;//表示圆周率的成员常量PI

publicdoubleRadius;//表示半径

//构造函数

publicCircle(doubleRadius)

{

this.Radius=Radius;

}

//计算圆的面积

publicdoubleArea()

{

return(PI*Radius*Radius);

}

}

classSample

{

publicstaticvoidMain()

{

//声明类Circle的一个实例c

Circlec=newCircle(6.6);

Console.WriteLine("圆的半径是{0}",c.Radius);

Console.WriteLine("圆的面积是{0}",c.Area());

}

}

程序执行结果:

圆的半径是6.6

圆的面积是136.847773656

 

3.2.6构造函数和析构函数

1、构造函数

⏹构造函数的函数名和类的名称一样。

⏹由于系统在对象实例化的同时自动调用构造函数,因此构造函数适合于为需要赋初始值的变量赋初值。

⏹构造函数可以重载(函数名相同,但参数类型或参数个数不同)。

⏹当某个类没有构造函数时,系统将自动为其创建构造函数,这种构造函数称为默认构造函数。

⏹构造函数的类型修饰符总是public。

如果是private,则表示这个类不能实例化,这通常用于只含有静态成员的类中。

⏹构造函数由于不需要显式调用,因而不用声明返回类型。

⏹构造函数可以带参数也可以不带参数。

//ch3_6.cs

usingSystem;

publicclassEmployee

{

publicstringname;//员工姓名

publicdecimalsalary;//员工薪水

//第一个构造函数不带参数

publicEmployee(){;}

//第二个构造函数可接受员工姓名

publicEmployee(stringname)

{

this.name=name;

}

//第三个构造函数可接受员工姓名和薪水

publicEmployee(stringname,decimalsalary)

{

this.name=name;

this.salary=salary;

}

}

publicclassSample

{

publicstaticvoidMain()

{

//没有传入任何参数,则调用第一个构造函数

Employeee1=newEmployee();

Console.WriteLine("员工姓名={0}",e1.name);

Console.WriteLine("薪水={0}元\n",e1.salary);

//传入一个员工姓名参数,则调用第二个构造函数

Employeee2=newEmployee("木林森");

Console.WriteLine("员工姓名={0}",e2.name);

Console.WriteLine("薪水={0}元\n",e2.salary);

//传入员工姓名和薪水参数,则调用第三个构造函数

Employeee3=newEmployee("木林森",6000);

Console.WriteLine("员工姓名={0}",e3.name);

Console.WriteLine("薪水={0}元",e3.salary);

}

}

程序执行结果:

员工姓名=

薪水=0元

员工姓名=木林森

薪水=0元

员工姓名=木林森

薪水=6000元

2、析构函数

⏹析构函数的名称:

在类名前加一个~符号。

⏹析构函数在对象销毁时运行,常用来处理对象用完后的收尾工作(对象在运行过程中动态申请内存的回收工作)。

⏹析构函数不能带有参数,不能拥有访问修饰符,不能显式地被调用。

⏹析构函数不能被继承,也不能被用户显式调用。

⏹如果类没有析构函数,系统自动调用默认的析构函数,如果有则需要用户来完成内存的回收和其他操作。

3.3方法

在C#中,任何数据和操作都必须封装到类中,不再有全局变量、全局常数和全局方法。

用户对类的操作大部分体现在对方法的使用上。

3.3.1方法的声明

方法是类中完成某一个或几个操作行为的成员。

它的声明格式为:

方法修饰符返回类型方法名(方法形式参数列表)

{

方法实现部分;

};

方法修饰符:

new、public、protected、internal、private、static、virtual、sealed、override、abstract、extern。

⏹static:

表明这个方法只能访问类中的静态成员,没有static的方法可以访问类中任意成员。

⏹virtual:

有virtual的方法称为虚方法,反之,称为非虚方法。

虚方法的执行方式可以被派生类改变,这种改变是通过重载实现。

⏹extern:

外部方法。

⏹返回类型:

合法的C#数据类型。

在方法的实现部分,可以通过return语句返回该数据类型。

⏹形参表:

值参数(不含任何修饰符)、引用参数(以ref修饰符声明)、输出参数(以out修饰符声明)、数组参数(以params修饰符声明)。

3.3.2值参数和引用参数

值参数:

传递参数时,编译器将实参的值做一个副本传给方法。

当在方法中改变了值,所作的变动只影响副本,而不影响实参本身。

引用参数:

传递参数时,编译器将实际值在内存中的地址传给方法。

当在方法中改变了值时,实参的值也将改变。

//ch3_7.cs

usingSystem;

classSample

{

//按值传递参数

staticvoidSwapVal(inta,intb)

{

inttmp=a;

a=b;

b=tmp;

}

//按引用传递参数

staticvoidSwapRef(refinta,refintb){

inttmp=a;

a=b;

b=tmp;

}

staticvoidMain(){

intx=10,y=20;

SwapVal(x,y);//调用SwapVal()方法

Console.WriteLine("按值传递后,x={0},y={1}",x,y);

SwapRef(refx,refy);//调用SwapRef()方法

Console.WriteLine("按引用传递后,x={0},y={1}",x,y);

}

}

程序运行结果:

按值传递后,x=10,y=20

按引用传递后,x=20,y=10

3.3.3输出参数

输出参数:

用于传递方法返回的数据。

与引用参数类似,输出参数也不必开辟新的内存区域。

与引用参数的区别是,调用方法时无需对输出参数的实参进行初始化。

//ch3_8.cs

usingSystem;

classSample

{

//SplitPath()方法用于将路径path分解为文件夹fldr和

//文件名fname。

path是值参数,而fldr和fname是输出参数

staticvoidSplitPath(stringpath,outstringfldr,outstringfname)

{

inti=path.Length;

while(i>0){

charc=path[i-1];

if(c=='\\'||c=='/'||c==':

')break;

i--;

}

fldr=path.Substring(0,i);

fname=path.Substring(i);

}

staticvoidMain(){

stringpath,fldr,fname;

path="c:

\\MyDoc\\AspNet\\temp.cs";

SplitPath(path,outfldr,outfname);

Console.WriteLine("将{0}分解后,得到",path);

Console.WriteLine("文件夹{0}",fldr);

Console.WriteLine("文件名{0}",fname);

}

}

程序运行结果:

将c:

\MyDoc\AspNet\temp.cs分解后,得到

文件夹c:

\MyDoc\AspNet\

文件名temp.cs

 

3.3.4数组参数

数组参数要用修饰符params。

当形参表中包含数组参数时,该参数必须位于最后面。

数组参数只能是一维的,如string[]和string[][]都可以作为数组参数,而string[,]则不能作为数组参数。

//ch3_9.cs

usingSystem;

classSample

{

//Sort()方法用于对数组进行排序

staticvoidSort(paramsint[]args)

{

inttmp;

for(inti=0;i

for(intj=0;j

if(args[i]

tmp=args[i];

args[i]=args[j];

args[j]=tmp;

}

}

staticvoidMain(){

int[]a={11,7,9,1,5,3};

Sort(a);

Console.Write("11,7,9,1,5,3的排序结果是:

");

for(inti=0;i

Console.Write("{0}",a[i]);

Console.WriteLine();

}

}

程序执行结果:

11,7,9,1,5,3的排序结果是:

1357911

3.3.5静态方法与非静态方法

⏹静态方法:

使用了static修饰符的方法,它不属于某一个具体的实例,只能访问类中的静态成员。

⏹非静态方法:

没使用static修饰符的方法,它可访问类中的任何成员。

//ch3_10.cs

classSample

{

intx;

staticinty;

//F()是非静态方法

voidF(){

x=1;//正确,等价于this.x=1

y=1;//正确,等价于Sample.y=1

}

//G()是静态方法

staticvoidG(){

x=1;//错误,在静态方法中不能访问非静态成员x

y=1;//正确,在静态方法能访问静态成员y

}

//Main()是静态方法

staticvoidMain(){

Samples=newSample();

s.x=1;//正确

s.y=1;//错误,不能在类的实例中访问静态成员y

Sample.x=1;//错误,不能用类名访问非静态成员x

Sample.y=1;//正确,能通过类名访问静态成员y

}

}

3.3.6方法重载

方法重载:

方法名相同,但参数类型或参数个数不同。

与构造函数重载相似。

//ch3_11.cs

usingSystem;

publicclassEmployee

{

publicstringname;//员工姓名

publicintage;//员工年龄

publicdecimalsalary;//员工薪水

//构造函数可接受员工姓名、年龄和薪水

publicEmployee(stringname,intage,decimalsalary)

{

this.name=name;

this.age=age;

this.salary=salary;

}

//比较员工的年龄大小

publicintmax(intx,inty)

{

if(x>y)

returnx;

else

returny;

}

//比较员工的薪水高低

publicdecimalmax(decimalx,decimaly)

{

if(x>y)

returnx;

else

returny;

}

publicstaticvoi

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 表格模板 > 表格类模板

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1