第3章 在C#中实现OOP.ppt_第1页
第3章 在C#中实现OOP.ppt_第2页
第3章 在C#中实现OOP.ppt_第3页
第3章 在C#中实现OOP.ppt_第4页
第3章 在C#中实现OOP.ppt_第5页
已阅读5页,还剩87页未读 继续免费阅读

下载本文档

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

文档简介

1、第3章 在C#中实现OOP,3.1 面向对象的基本概念 3.2 C#中的类 3.3 对象 3.4 构造函数和析构函数 3.5 静态成员和实例成员 3.6 方法 3.7 C#中的继承,3.8 属性与索引器 3.9 抽象类、抽象方法与抽象属性 3.10 接口 3.11 多态性的实现,面向对象编程(Object-Oriented Programming,OOP)是一种功能非常强大的编程方法,可以更容易地维护和重使用已有的代码,执行非常复杂的任务。它使代码有非常直观、自然的结构,这是过程化语言所不具备的。C#就是一种功能非常强大的面向对象的编程语言。,3.1 面向对象的基本概念,3.1.1 类和对象

2、3.1.2 封装、继承和多态,3.1.1 类和对象,面向对象思想来源于对现实世界的认知。现实世界缤纷复杂、种类繁多,难于认识和理解。但是聪明的人们学会了把这些错综复杂的事物进行分类,从而使世界变得井井有条。 面向对象编程也采用了类的概念,把事物编写成一个个“类”。,对象则是类的具体实例,是客观世界的个体或实体。,3.1.2 封装、继承和多态,在面向对象的世界中,大多数都是以类作为数据的基本单位。类将数据和操作数据的方法结合成一个单位,这就是封装。 继承是面向对象编程最重要的特性之一,任何类都可以从另外一个类继承,这就是说,这个类拥有它继承的类的所有成员。在面向对象的编程中,类的创建是沿着树型结

3、构发展起来的,正是通过继承的机制,实现了代码的重用。被继承的类称为父类或基类,继承的类称为派生类或子类。,多态性是在对象体系中把设想和实现分开的手段,意味着几个不同的对象具有相同名字的方法(函数或者事件),但每个对象为该方法提供的参数和实现过程都可能不同。,3.2 C#中的类,3.2.1 类的声明 3.2.2 类成员 3.2.3 类成员的访问控制,类是一种数据结构,它可以包含数据成员、函数成员(方法、属性、事件、索引器、运算符、实例构造函数、析构函数和静态构造函数)。,3.2.1 类的声明,C#中,类的声明语法如下: 类的属性 类修饰符 class 类名 :基类或任何接口列表 /类成员 ,3.

4、2.2 类成员,类的成员可以分为两大类:类本身所声明的和从基类中继承而来的。,3.2.3 类成员的访问控制,对一个类的成员可以通过指定不同的访问修饰符实现对该成员的访问控制。,3.3 对象,类是抽象的,要使用类定义的功能,就必须实例化类,即创建类的对象。 类与对象的关系可以比喻为车型设计和具体的车:类就像车型设计一样说明了车所应该具备的所有属性和功能,但是车型设计并不是车,你不能发动和驾驶车型;对象就像根据车型设计制造出的车,它们都具备车型设计所描述的属性和功能,车是能发动和驾驶的。,创建对象的语法如下: 类名 对象 = new 类名(参数表); 或 类名 对象; 对象 = new 类名(参数

5、表); 其中,参数表是可选的。,用new创建一个类的对象时,将为对象分配一块内存,每一个对象都有不同的内存。代表对象的变量存储的是存放对象的内存的地址。因此,两个不同的对象,即使它们的所有成员的值或代码都相同,它们也是不相等的。就像同一型号的每一辆车都不相同一样,用同一个类创建出来的不同对象也是不同的。,【例3-1】展示不同对象之间的关系。,【例3-2】展示相同的对象(对象赋值)。,3.4 构造函数和析构函数,3.4.1 构造函数 3.4.2 析构函数,3.4.1 构造函数,构造函数是类的一种特殊的方法成员,作用是在创建对象时初始化对象的数据成员。,1. 构造函数的声明,声明构造函数的形式为:

6、 访问修饰符 类名( 参数列表 ) /构造函数的主体 ,注意:,注意: 构造函数不允许有返回类型包括void类型。 构造函数的名称必须与类名相同。 在构造函数中不要做对类的实例进行初始化以外的事情,也不要尝试显式地调用构造函数。 一个类定义必须且至少有一个构造函数,如果定义类时,没有声明构造函数,系统会自动提供一个默认的无参构造函数供创建类对象时使用。如果声明了构造函数,系统将不再提供默认的构造函数。,【例3-3】构造函数的声明及特点体现。,2. 带参数的构造函数,【例3-4】一个类中多个构造函数的声明及应用。,3. this关键字,在类的实例构造函数和实例函数成员中,关键字this表示当前的

7、类实例或者对象的引用。当在实例构造函数或方法内使用了与字段名相同的变量名或参数名时,可以使用this来区别字段和变量或者参数。,4. 私有构造函数,一般地,构造函数总是public 类型的。如果构造函数被声明为private类型,则这个构造函数不能从类外访问,因此也不能用来在类外创建对象,通常用于只含有静态成员的类,这样的类不需要实例化,就能通过类名来引用所有的静态成员。,5. 静态构造函数,静态构造函数用于实现初始化类(而不是初始化实例或对象)所需的操作。声明静态构造函数只需在构造函数名前使用关键字static。类的静态构造函数在给定程序中至多执行一次。,3.4.2 析构函数,析构函数用于实

8、现销毁类的实例所需的操作,并释放实例所占的内存。,析构函数具有如下特征: 名称由类名前面加上“”字符构成。 没有返回值类型(甚至也不能使用void),也不能返回值。 没有参数。 一个类只能有一个析构函数。 析构函数是自动调用的,它不能被显式调用。,【例3-6】析构函数的例子。,3.5 静态成员和实例成员,静态成员 :在类的成员的类型或者返回值类型前面加上关键字static 非静态成员 :没有用static修饰的成员都是实例成员,静态成员具有下列特征:,静态成员必须通过类名使用“ . ”运算符来引用,而不能用对象来引用。 一个静态字段只标识一个存储位置。无论创建了一个类的多少个实例,它的静态字段

9、在内存中都只占同一块区域。 静态函数成员(方法、属性、事件、运算符或构造函数)不能作用于具体的实例,,实例成员具有以下特点:,实例成员必须通过对象名使用 . 运算符来引用,而不能用类名来引用。 类的实例字段属于类的实例所有,每创建一个类的实例,都在内存中为实例字段开辟了一块区域。类的每个实例分别包含一组该类的所有实例字段的副本。 实例函数成员(方法、属性、索引器、实例构造函数或析构函数)作用于类的给定实例,在它们的代码体内可以直接引用类的静态和实例成员。,【例3-7】静态字段与实例字段、静态方法与实例方法使用上的区别。,【例3-8】多个对象下的静态字段与实例字段的存储特点。,3.6 方法,3.

10、6.1 声明方法 3.6.2方法调用 3.6.3 静态方法,方法是把一些相关的语句组织在一起,用于解决某一特定问题的语句块。方法同样遵循先声明后使用的规则。方法必须放在类定义中,也就是说,方法必须是某一个类的方法。一种方法至少由下列部分组成:返回类型、方法名称、参数表和方法体。,3.6.1 声明方法,方法的声明格式为: 方法修饰符 返回类型 方法名(形参表) /方法体 ,1方法修饰符 2方法返回值类型 3方法名 4方法的形参表 5方法体,3.6.2方法调用,方法调用一般格式为: 对象(类). 方法名( 实参表 ),注意:,调用和被调用的方法名必须一致。 调用方法的实参表和被调用方法的形参的类型

11、、个数和顺序必须一致。 方法中定义的形参,在方法未被调用之前,它们并不占用内存中的存储单元。只有在方法被调用时,形参才被分配存储单元,在调用结束后,形参所占的存储单元被释放。,1方法调用中的参数传递,如果一个方法有形式参数,方法的调用实际上就是将实际参数传递给形式参数,执行方法体的过程。在C#中参数的传递有两种方式:以传值方式传递参数和以传引用方式传递参数。,(1)以传值方式传递参数,如果声明方法的参数时,参数前没有ref或out修饰符,则调用方法时,以传值方式向方法传递参数。C#中默认的参数传递方式是以传值方式传递参数。,(2)以传引用方式传递参数,以传值方式传递参数时,由于参数传递是单向的

12、,即只能由实参传递给形参,而不能由形参返回给实参,因此在方法执行时,无法更改实参本身的值。那么在方法内对形参的修改如何才能返回给实参呢?此时可考虑采用“以传引用的方式传递参数”。以传引用方式传递参数的特点是:不再为形参创建新的存储位置,实参与形参共用同一个存储位置,这样对形参的任何修改就会直接反映给实参了。,3.6.3 静态方法,在方法声明时使用了static修饰符的方法是静态方法;没有使用static符修饰的方法就是实例方法。静态方法是一个特殊的成员方法,不属于类的某一个具体的实例或对象,而是属于类本身。和使用其他静态成员一样,访问静态方法只能使用类名,而不需要创建对象,也不能使用对象名来引

13、用,即使用户具有类的实例。,【例3-17】声明一雇员类,在雇员类中声明一方法tellAboutSelf,该方法返回雇员的姓名、工资和税金。再声明一Tax类,在该类声明一个静态方法CalculateTax,计算该方法指定的雇员的税金。雇员的税金为雇员工资的2.8%。编写程序,创建雇员实例,然后输出雇员信息(姓名、工资和税金)。,3.7 C#中的继承,3.7.1 继承与base关键字 3.7.2 C#方法的重写 3.7.3重载、重写和隐藏的比较,继承是面向对象程序设计的主要特征之一,它可以使代码重用,可以节省程序设计的时间。现实世界中的许多实体之间不是相互孤立的,它们往往具有共同的特征也存在内在的

14、差别。人们可以采用层次结构来描述这些实体之间的相似之处和不同之处。,3.7.1 继承与base关键字,1.继承的实现 C#中类继承的语法形式为: class 派生类:基类 派生类代码; ,【例3-18】继承的使用(一),【例3-19】继承的使用(二),2.base关键字 base关键字主要是用于派生类中调用基类成员的方法,也可以使用base关键字调用基类的构造函数。,【例3-20】使用base关键字调用基类构造函数,3.7.2 C#方法的重写,在基类中的成员可能执行与派生类中同名成员的不同的任务,或者派生类中成员必须提供基类中对应抽象成员的实现方式,这种过程称为重写。,【例3-21】重写方法,

15、3.7.3重载、重写和隐藏的比较,1隐藏从基类继承的成员 使用 new 修饰符可以显式隐藏从基类继承的成员。隐藏继承的成员意味着该成员的派生版本将替换基类版本。若要隐藏继承的成员,请使用相同名称在派生类中声明该成员,并用 new 修饰符修饰它。若派生类中的成员和基类的成员使用相同的名称、相同的参数和类型,但未使用new修饰符修饰它,程序编译和运行不会发生错误,但会发出警告。,【例3-22】隐藏从基类继承的成员,2重载、重写与隐藏的比较 重载、重写和隐藏是很容易混淆的概念。虽然所有这三种技术都能创建同名的成员,但它们之间有一些重要的差别。,重载的成员用于提供方法的不同版本,这些版本具有相同名称但

16、是接受不同数量的参数或者接受不同数据类型的参数。 重写的属性或者方法用于替换基类中不适合在派生类中被继承的方法或属性。重写的成员必须接受同一数据类型和参数数量。,隐藏的成员用于局部替换具有更广泛范围的成员。任何类型都可隐藏任何其他类型。,3.8 属性与索引器,3.8.1属性 3.8.2索引器,3.8.1属性,属性和字段一样,属性的值表示的是类或对象的状态值。属性是字段的自然扩展,它们都是具有关联类型的命名成员,而且访问字段和属性的语法是相同的。然而,与字段不同,属性不表示存储位置。属性有访问器(accessor),这些访问器指定在它们的值被读取或写入时需执行的语句。因此属性提供了一种机制,它把

17、读取和写入对象的某些性质与一些操作关联起来。,属性是类的成员。属性的声明形式如下: 修饰符类型属性名 get get访问器体 set set访问器体 ,【例3-23】属性的创建与使用,3.8.2索引器,索引器是C#特有的一种访问技术。假设在类中定义一个数组,在类中访问数组元素时,传统的做法是在对象名后指定数组名,同时指定要访问元素的索引值,才能进行赋值等操作。用C#索引器技术,可以为数组创建索引器,然后通过从对象直接指定索引的方式来访问数组里的元素。这两种方式从功能上说是等价的。,索引器的基本声明形式为: 修饰符类型 this参数表 get get访问器体 set set访问器体 ,【例3-2

18、4】一维索引器的创建与使用示例,【例3-25】二维索引器的创建与使用示例,3.9 抽象类、抽象方法与抽象属性,3.9.1 抽象类 3.9.2 抽象方法 3.9.3抽象属性,3.9.1 抽象类,有时基类并不与具体的事物相联系,而只是表达一种高度的概括,为此,C#中引入抽象类的概念。在类定义的前面加上abstract关键字,那么这个类就是抽象类了。,3.9.2 抽象方法,由于抽象类本身表达的是抽象的概念,因此类中的许多方法并不定要有具体的实现,而只是留出一个接口来作为派生类的公共界面。例如,“图形”这个类是抽象的,它的成员方法“计算图形面积”也就没有实际的意义。面积只对“图形”派生类比如“圆”,“

19、三角形”这些非抽象的概念才有效,那么就可以把基类“图形”的成员方法“计算图形面积”声明为抽象的,具体的实现交给派生类通过重写来实现。,【例3-26】抽象方法使用示例,3.9.3抽象属性,当属性声明包含abstract修饰符时,则称该属性为抽象属性。抽象属性声明不提供属性访问器的实现,它只声明该类支持属性,而将访问器实现留给派生类。抽象属性和抽象方法一样,不能再使用static或virtual修饰符。包含抽象属性的类必须定义为抽象类。,【例3-27】抽象属性使用示例,3.10 接口,3.10.1 接口的声明 3.10.2 接口的实现 3.10.3 抽象类与接口的区别,在C#中类只能实现“单一继承

20、”,要实现多重继承,必须使用接口。也就是说,类可以实现无数多个接口,但仅能从一个抽象类(或任何其他类)继承。,3.10.1 接口的声明,使用interface关键字声明接口的语法是: 属性信息修饰符 interface 接口名称: 基接口列表 接口体 ,3.10.2 接口的实现,派生类不仅可以从基类继承,也可以从接口继承,而接口只是由方法、属性、索引器和事件组成的框架,故使用一个接口只有通过类的继承来实现。 一个接口定义一个协定,实现接口的类必须遵守其协定,即在类声明中定义接口的每个项目,否则代码将不被编译。类通过在其声明语句中包括冒号和接口名来表示它正在实现这个接口。,【例3-28】一个接口实现示例,【例3-29】多重接口实现示例,【例3-30】类继承并实现多个接口的示例,3.10.3 抽象类与接口的区别,派生类只能继承一个基类,即只能直接继承一个抽象类(但可以用一个继承链包含多个抽象类)。相反,类可以使用任意多个接口。但这不会产生太大的区别。而且这两种情况得到的效果是类似的,只是采用接口的方式略有不同。,抽象类可以拥有抽象成员(没有代码体,且必须在派生类中实现,否则派生类本身必须也是抽象的)和非抽象成员(它们拥有代码体,也可以是虚拟的,这样就可以在派生类中重写)。另一方面,接口成员必须都在使用接口的类上实现

温馨提示

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

评论

0/150

提交评论