C# Ch5面向对象的高级程序设计_第1页
C# Ch5面向对象的高级程序设计_第2页
C# Ch5面向对象的高级程序设计_第3页
C# Ch5面向对象的高级程序设计_第4页
C# Ch5面向对象的高级程序设计_第5页
已阅读5页,还剩54页未读 继续免费阅读

下载本文档

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

文档简介

第五章面向对象的高级程序设计

1.总体要求掌握静态类与静态类成员的定义与使用。理解类的继承性与多态性,掌握其应用方法。理解抽象类、接口的概念,掌握抽象类与接口的定义及使用方法。理解嵌套类、分部类和命名空间的概念,掌握嵌套类、分部类和命名空间的使用方法。2.相关知识点熟悉C#的结构、类、数组的区别。熟悉类和类成员的定义与使用熟悉方法的定义与使用等基本操作。3.学习重点静态成员与静态类类的继承性与多态性抽象类与接口定义与使用。4.学习难点静态成员的作用,静态方法和实例方法的区别多态的概念和实现,虚方法和抽象方法的区别接口的作用和使用,抽象方法和接口的区别第五章面向对象的高级程序设计第五章面向对象的高级程序设计主要内容5.1静态成员与静态类5.2类的继承性与多态性5.3抽象类与接口5.4嵌套类、分部类与命名空间5.1静态成员与静态类

5.1.1静态成员5.1.2静态构造函数5.1.3静态类返回5.1.1静态成员

静态成员通过static关键字来标识,可以是静态方法、字段、属性或事件。静态成员与非静态成员的不同在于:静态成员属于类,而不属于类的实例,因此需要通过类而不是通过类的实例来访问;而非静态成员则总是与特定的实例(对象)相联系。在实际应用中,当类的成员所引用或操作的信息是关于类而不是类的实例时,就应该设置为静态成员。例如,想统计同类对象的数量,就可使用静态字段和静态方法来实现5.1.1静态成员

【实例5-1】利用静态成员统计人数。5.1.2静态构造函数类的构造函数也可以是静态的,静态构造函数不是为了创建对象而设计的,而是用来初始化类,只有非静态的构造函数才用来创建对象(用于创建对象的构造函数称为实例构造函数)。由于静态构造函数并不对类的特定实例进行操作,所以也称为全局或共享构造函数。在C#应用程序中,不能直接调用静态构造函数。静态构造函数在类的第一个实例创建之前或者调用类的任何静态方法之前执行,而且最多执行一次。因此,静态构造函数适合于对类的静态数据成员进行初始化。5.1.2静态构造函数静态构造函数可以与实例构造函数共存,其一般形式如下:static静态构造函数名(){//语句;}其中,静态构造函数名与类名相同,声明静态构造函数时不能带访问修饰符(如public),并且不能有任何参数列表和返回值。5.1.2静态构造函数我们可以在【实例5-1】的基础上增加一个静态构造函数,结果就会不同5.1.3静态类静态类使用static关键字来声明,以指示它仅包含静态成员,不能使用new关键字创建静态类的实例。在实际应用中,当类中的成员不与特定对象关联的时候,就可以把它创建为静态类。静态类有下以特点:(1)静态类仅包含静态成员;(2)静态类不能被实例化;(3)静态类是密封的;(4)静态类不能包含实例构造函数5.1.3静态类由于静态类是密封的,因此不可被继承。静态类不能包含实例构造函数,但仍可声明静态构造函数,以分配初始值或设置某个静态状态。(关于密封和继承将在下节进行讨论)。静态类的优点如下:(1)编译器能够自动执行检查,以确保不添加实例成员;(2)静态类能够使程序的实现更简单、迅速,因为不必创建对象就能调用其方法。5.2类的继承性与多态性5.2.1类的继承性5.2.2类的多态性返回5.2.1类的继承性当一个类从另一个类派生出来时,派生类就具有了基类中的所有成员,这样,基类中定义这些成员的代码,不需要在派生类定义中重写,在派生类定义中,只需定义派生类自己的成员即可。这样,既提高了代码的重用性,从而提高了程序设计的效率,又提供了已有程序设计的可扩展性。类的继承为面向对象程序设计构建一个分层类结构体系创造了条件,而.NET框架类库就是一个庞大的分层类结构体系。其中Object类是一个最上层的基类,其他所有类都是直接或间接由Object类继承而来的。即使用户自定义的类没有指定继承关系,系统仍然将该类作为Object类的派生类。5.2.1类的继承性在C#中,类的继承遵循以下原则:(1)派生类只能从一个类中继承,即单继承。(2)派生类自然继承基类的成员,但不能继承基类的构造函数(3)类的继承可以传递,例如:假设类C继承于类B,类B又继承类A,那么C类即具有类B和类A的成员,可以认为类A是类C的祖先类。5.2.1类的继承性1.派生类的声明在C#中,派生类可以拥有自己的成员,也可以隐式地从它的基类继承所有成员,包括方法、字段、属性和事件,但私有成员、构造函数和析构函数等除外。另外,派生类只能从一个类中继承,即单继承。C#中声明派生类的一般形式如下:[访问修饰符]class类名[:基类名]{

类的成员;}5.2.1类的继承性2.构造函数的调用在C#中,派生类不能继承其基类的构造函数,但是,在创建对象时,会调用构造函数,为对象分配内存并初始化对象的数据。创建派生类对象时,为完成其基类部份的成员初始化,会调用基类的构造函数。其调用构造函数的顺序是先调用基类构造函数,再调用派生类的构造函数,以完成数据成员分配内存空间并进行初始化的工作。类的继承可以传递,例如:假设类C继承于类B,类B又继承类A,那么C类即具有类B和类A的成员,可以认为类A是类C的祖先类。在这种情况下,构造函数的调用次序按由高到低顺序依次调用,即先调用A的构造函数,再调用B的构造函数。最后调用C的构造函数。5.2.1类的继承性publicclassA{publicA(){}}publicclassB:A{publicB(){}}5.2.1类的继承性新类(即派生类)将获取基类的所有非私有数据和行为以及新类为自己定义的所有其他数据或行为。因此,新类具有两个有效类型:新类的类型和它继承的类的类型。在上面的示例中,类B既是有效的B,又是有效的A。访问B对象时,可以使用强制转换操作将其转换为A对象。强制转换不会更改B对象,但您的B对象视图将限制为A的数据和行为。将B强制转换为A后,可以将该A重新强制转换为B。并非A的所有实例都可强制转换为B,只有实际上是B的实例的那些实例才可以强制转换为B。如果将类B作为B类型访问,则可以同时获得类A和类B的数据和行为。5.2.1类的继承性【实例5-2】继承中的构造函数调用演示。5.2.1类的继承性如果把基类的构造函数publicAnimal()改为如下形式:publicAnimal(stringname,intage){=name;this.age=age;}则编译时如出现“Animal不包含采用0个参数的构造函数”的错误,这是因为当创建派生类对象时,系统默认调用基类的默认构造函数(即无参构造函数),而当基类没有默认构造函数或想调用基类的带参的构造函数时,需要使用base关键字。其格式如下:public派生类构造函数名(形参列表):base(向基类构造函数传递的形参列表){}5.2.1类的继承性【实例5-3】调用基类带参构造函数演示。5.2.1类的继承性3.密封类为了阻止一个类的代码被其他类继承,可以使用密封类,因为在.NET中,加载密封类时将对密封类的方法调用进行优化,因此使用密封类可以提高应用程序的可靠性和性能。另外,软件开发者通过使用密封类还可以把自己的知识产权保护起来,避免他人共享代码。在C#中,添加关键字sealed可以声明密封类。5.2.2类的多态性多态性是面向对象程序设计的一个重要特征,多态的意思是一种事物有多种形态,即对象可以表示多个类型的能力称为多态性。如:通过继承,一个类可以用作多种类型:可以用作它自己的类型、任何基类型,或者在实现接口时用作任何接口类型。这称为多态性。多态性不仅对派生类很重要,对基类也很重要。任何情况下,使用基类实际上都可能是在使用已强制转换为基类类型的派生类对象。基类的设计者可以预测到其基类中可能会在派生类中发生更改的方面。例如,表示汽车的基类可能包含这样的行为:当考虑的汽车为小型货车或敞篷汽车时,这些行为将会改变。5.2.2类的多态性当派生类从基类继承时,它会获得基类的所有方法、字段、属性和事件。为了使用派生类能更改基类的数据和行为,C#提供了两种选择:一是使用新的派生成员替换基成员,二是重写虚拟的基成员。5.2.2类的多态性1.使用new关键字重新定义类的成员使用new关键字来定义与基类中同名的成员,即可替换基类的成员。如果基类定义了一个方法、字段或属性,则new关键字用于在派生类中创建该方法、字段或属性的新定义。new关键字应放置在要替换的类成员的返回类型之前。使用new

关键字时,调用的是新的类成员而不是已被替换的基类成员。这些基类成员称为隐藏成员。如果将派生类的实例强制转换为基类的实例,就仍然可以调用隐藏类成员。5.2.2类的多态性2.为了使派生类的实例完全接替来自基类的类成员,基类必须将该成员声明为虚拟的。通过在该成员的返回类型之前添加virtual关键字来实现的。然后,派生类可以选择使用override关键字而不是new,将基类实现替换为它自己的实现。用virtual和override关键字定义类成员基类中的声明格式:publicvirtual方法名称([参数列表]){}派生类的声明格式:publicoverride方法名称([参数列表]){}其中,基类与派生类中的方法名称与参数列表必须完全一致。5.2.2类的多态性【实例5-4】虚方法演示。5.2.2类的多态性当点击“创建子类对象并调用方法”按钮时,以子类对象做为实参,将调用子类的Eat方法,显示结果会不同无论在派生类和最初声明虚成员的类之间已声明了多少个类,虚成员都将永远为虚成员。如果类A声明了一个虚拟成员,类B从A派生,类C从类B派生,则类C继承该虚拟成员,并且可以选择重写它,而不管类B是否为该成员声明了重写。例如:publicclassA{publicvirtualvoidDoWork(){}}publicclassB:A{publicoverridevoidDoWork(){}}publicclassC:B{publicoverridevoidDoWork(){}}5.2.2类的多态性派生类可以通过将重写声明为密封的来停止虚拟继承。这需要在类成员声明中将sealed关键字放在override关键字的前面。publicclassC:B{publicsealedoverridevoidDoWork(){}}在上面的示例中,方法DoWork对从C派生的任何类都不再是虚方法,但它仍是C的实例的虚方法--即使将这些实例强制转换为类型B或类型A也是如此。派生类可以通过使用new关键字替换密封的方法,如下面的示例所示:publicclassD:C{publicnewvoidDoWork(){}}在此情况下,如果在D中使用类型为D的变量调用DoWork,被调用的将是新的DoWork。如果使用类型为C、B或A的变量访问D的实例,对DoWork的调用将遵循虚拟继承的规则,即把这些调用传送到类C的DoWork实现。5.2.2类的多态性使用virtual和override时要注意以下几点:(1)字段不能是虚拟的,只有方法、属性、事件和索引器才可以是虚拟的;(2)使用virtual修饰符后,不允许再使用static、abstract或override修饰符;(3)派生类对象即使被强制转换为基类对象,所引用的仍然是派生类的成员;(4)派生类可以通过密封来停止虚拟继承,此时派生类的成员使用sealedoverride声明。5.2.2类的多态性3.调用基类方法当派生类重载或覆盖基类方法后,如果想调用基类的同名方法,可以使用base关键字。如,在Dog类的Eat方法中,希望使用基类的Eat方法,可以用如下方法:publicoverridevoidEat(){base.Eat();}5.3抽象类与接口5.3.1抽象类5.3.2接口5.3.3抽象类与接口的比较返回5.3.1抽象类

抽象方法是指在基类的定义中,不包含任何实现代码的方法,实际上就是一个不具有任何具体功能的方法。这样的方法唯一的作用就是让派生类重写。而只要在类中包含一个抽象方法,该类即为抽象类。在抽象类中,也可以声明非抽象方法。1.抽象类与抽象方法的声明在C#中,抽象类和抽象方法使用关键字abstract声明,一般形式如下:publicabstractclass抽象类名{[访问修饰符]abstract返回值类型方法名([参数列表])}5.3.1抽象类抽象类具有以下特性:抽象类不能实例化。抽象类可以包含抽象方法和抽象访问器。不能用sealed修饰符修改抽象类,这意味着抽象类不能被继承。从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实实现。在方法或属性声明中使用abstract

修饰符以指示方法或属性不包含实现。抽象方法具有以下特性:抽象方法是隐式的虚方法。只允许在抽象类中使用抽象方法声明。因为抽象方法声明不提供实际的实现,所以没有方法体;方法声明只是以一个分号结束,并且在签名后没有大括号({})。5.3.1抽象类实现由一个重写方法override提供,此重写方法是非抽象类的一个成员。在抽象方法声明中使用static或virtual修饰符是错误的。除了在声明和调用语法上不同外,抽象属性的行为与抽象方法一样。在静态属性上使用abstract

修饰符是错误的。在派生类中,通过包括使用override修饰符的属性声明,可以重写抽象的继承属性。5.3.1抽象类抽象类中也可以有抽象属性。类的属性成员添加了abstract关键字后,就成了抽象属性。抽象属性不提供属性访问器的实现,它只声明该类支持的属性,而将访问器的实现留给派生类。抽象属性同样可以是只读的、只写的或可读写的属性。一般形式如下:publicabstract返回值类型属性名{get;set;}抽象类可以包含抽象的成员,如抽象属性和抽象方法,也可以包含非抽象的成员,甚至还可以包含虚方法。要注意的是,抽象成员必须在抽象类中声明,但抽象类不要求必须包含抽象成员5.3.1抽象类2.重载抽象方法抽象类中的抽象方法和抽象属性都没有提供实现,当定义抽象类的派生类时,派生类必须重载基类的抽象方法和抽象属性(如果派生类没有进行重载,则派生也必须声明为抽象类,即在类定义前加上abstract。这一点是与虚方法不同的,因为对于基类的虚方法,其派生类可以不重载。重载抽象类的方法和属性必须使用override关键字。重载抽象方法的格式为:publicoverride方法名称([参数列表]){}其中,方法名称和参数列表必须与抽象类中的抽象方法完全一致。当抽象类从基类继承虚方法时,抽象类可以使用抽象方法重写该虚方法。例如://compilewith:/target:librarypublicclassD{publicvirtualvoidDoWork(inti){//Originalimplementation.}}publicabstractclassE:D{publicabstractoverridevoidDoWork(inti);}publicclassF:E{publicoverridevoidDoWork(inti){//Newimplementation.}}如果将虚方法声明为抽象方法,则它对于从抽象类继承的所有类而言仍然是虚的。继承抽象方法的类无法访问该方法的原始实现。在前面的示例中,类F上的DoWork无法调用类D上的DoWork。在此情况下,抽象类可以强制派生类为虚方法提供新的方法实现。5.3.1抽象类【实例5-5】抽象方法和抽象类演示。5.3.2接口接口(interface)是C#的一种数据类型,属于引用类型。一个接口定义一个协定。接口可以包含方法、属性、事件和索引器,接口本身不提供它所定义的成员的实现,接口只指定实现该接口的类或结构必须提供的成员。实现某接口的类必须遵守该接口定义的协定,即必须提供接口成员的实现。1.接口的声明在C#中,声明接口使用interface关键字,一般形式如下:[访问修饰符]interface接口名[:基接口列表]{//接口成员}5.3.2接口接口成员可以是属性、方法、索引器和事件,不能包含字段、构造函数等。所有接口成员隐式地具有了public访问修饰符,因此,接口成员不能添加任何访问修饰符。下面示例定义了一个USB的接口,该接口包含了一个TransData方法签名和一个获到最大传输速率的只读属性。。interfaceIUsb{intMaxSpeed{get;}stringTransData(stringfrom,stringto);}5.3.2接口2.接口的实现接口主要用来定义一个规则,让企业内部或行业内部的软件开发人员按标准去实现应用程序的功能。因此,继承接口的类或结构必须实现接口中的所有属性、方法、索引器和事件,继承接口的方法与继承类相似3.接口的继承接口也可以继承其它接口,而接口可以多继承,即接口可以从多个接口继承,基接口名之间用逗号分隔。

5.3.2接口4.多重接口实现C#不允许多重类继承,但是C#允许多重接口实现,这意味着一个类可以实现多个接口,如果一个Mobile类支持USB,也可以支持Bluetooth,我们就应该同时实现IUsb和IBluetooth接口,在继承时,两个接口之间用逗号分隔。其类的头部如下所示:publicclassMobile:IUsb,IBluetooth如果类Mobile是类phone的派生子类,也可以同时继承phone类。但要注意,基类必须在所有的接口之前,如:publicclassMobile:Phone,IUsb,IBluetooth5.3.2接口5.访问接口的方法当类Mp3实现了IUsb后,我们可以通过MP3类的对象访问IUsb的成员,就好象是Mp3类的成员一样:Mp3m=newMp3();lblShow.Text=m.TransData("计算机","MP3设备");或者我们也可以将Mp3对象转换成接口类型,然后用这个接口来访问方法:Mp3m=newMp3();IUsbiu=(IUsb)m;lblShow.Text=iu.TransData("计算机","MP3设备");5.3.2接口【实例5-6】接口演示。5.3.3抽象类与接口的比较抽象类是一种不能实例化的类,抽象类可以包含抽象成员,也可以包含非抽象成员,即抽象类可以是完全实现的,也可以是部分实现的,或者完全不实现的。抽象类可以用来封装所有派生类的通用功能。与抽象类不同的是,接口顶多像一个完全没有实现的只包含抽象成员的抽象类,因此无法使用接口来封装所有派生类的通用功能,接口更多地用来制定程序设计开发规范,接口的代码实现由开发者完成。例如,有关XML文档的处理,万维网联盟(W3C)就制定了一个DOM(文档对象模型)规范,而具体的代码实现由诸如Microsoft、Sun等公司去实现。5.3.3抽象类与接口的比较C#规定一个类只能从一个基类派生,但允许从多个接口派生。例如,如果把实例5-6中的两个接口改为抽象类,则不允许同时使用它们来派生Mobile类。抽象类为管理组件版本提供了一个简单易行的方法。通过更新基类,所有派生类都将自动进行相应改动。而接口在创建后就不能再更改,如果需要修改接口,必须创建新的接口。5.4嵌套类、分部类与命名空间5.4.1嵌套类5.4.2分部类5.4.3命名空间返回5.4.1嵌套类在类的内部或结构的内部定义的类型称为嵌套类型,又称内部类型。不论是类还是结构,嵌套类型均默认为private,嵌套类型也可以设置为public、internal、protected或protectedinternal。嵌套类型通常需要实例化为对象之后,才能引用其成员,其使用方法与类的普通成员使用基本相同。【实例5-7】使用嵌套类计算长方形面积。5.4.2分部类分部类允许将类、结构或接口的定义拆分到两个或多个源文件中,让每个源文件只包含类型定义的一部分,编译时编译器自动把所有部分组合起来进行编译。有了分部类,一个类的源代码可以分布于多个独立文件中,在处理大型项目时,过去很多只能由一个人进行的编程任务,现在可以由多个人同时进行,这样将大大加快了程序设计的工作进度。有了分部类,使用自动生成的源代码时,无需重新创建源文件便可将代码添加到类中。事实上,当创建Windows应用程序或Web应用程序时,就是在VisualStudio2010自动生成源代码的基础之上专注于项目的业务处理,编译时VisualStudio2010会自动把编写的代码与自动生成的代码进行合并编译。5.4.2分部类处理分部类的定义时需遵循以下几个规则:(1)同一类型的各个部分的所有分部类的定义都必须使用partial进行修饰。(2)如果将任意部分声明为抽象的,则整个类型都被视为抽象的。如果将任意部分声明为密封的,则整个类型都被视为密封的。(3)partial修饰符只能出现在紧靠关键字class、struct或interface前面的位置。(4)分部类的各部分或者各个源

温馨提示

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

评论

0/150

提交评论