版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
VisualC#.NET程序设计第四讲VisualC#.NET面向对象程序设计沈志忠zzshen78@163.com北京科技大学信息工程学院第7章
面向对象的程序设计
本章要点:
面向对象的基本概念
类的定义与对象的声明
构造函数和析构函数
类的静态成员和实例成员
方法重载及运算符重载的编程实现
类的继承与多态性的编程实现
类的属性的实现7.1循序渐进学理论
7.1.1面向对象程序设计概述
1.面向对象程序设计的由来面向对象的程序设计是一种基于结构分析的、以数据为中心的程序设计方法。面向对象的程序设计方法总体思路是:将数据及处理这些数据的操作都封装(Encapsulation)到一个称为类(Class)的数据结构中,在程序中使用的是类的实例——对象。对象是代码与数据的集合,是封装好了的一个整体,对象具有一定的功能。也就是说对象是具有一定功能的程序实体。程序是由一个个对象构成的,对象之间通过一定的“相互操作”传递消息,在消息的作用下,完成特定的功能。
2.面向对象程序设计的基本概念
(1)类和对象通常把具有同样性质和功能的东西所构成的集合叫作类。
(2)属性、方法与事件属性是对象的状态和特点。
方法是对象能够执行的一些操作,它体现了对象的功能。事件是对象能够识别和响应的某些操作。(3)封装
所谓的封装,就是将用来描述客观事物的一组数据和操作组装在一起,形成一个类。
(4)继承类之间除了有相互交流或访问的关系以外,还可能存在着一种特殊的关系,这就是继承。在VisualC#中只支持单继承,即一个派生类只能有一个基类。(5)重载重载指的是方法名称一样,但如果参数不同,就会有不同的具体实现。重载主要有两类:方法重载及运算符重载。
(6)多态性
所谓多态性就是在程序运行时,面向对象的语言会自动判断对象的派生类型,并调用相应的方法。7.1.2类和对象的声明
1.类的声明[格式]:class类名[:基类类名] {
成员定义列表;
}【例7-1】定义一个Student类,用来对学生的信息和功能进行描述。假设学生具有学号、姓名、年龄、性别、平均成绩等特征,并且具有设置学生特征和显示学生特征的功能。2.对象的声明
[格式]:类名 实例名=new类名([参数]);3.类的成员(1)类成员的分类
类的具体成员如下。
常量:用来定义与类相关的常量值。
域(字段):类中的变量,相当于C++中的成员变量。
方法:完成类中各种计算或功能的操作。
属性:定义类的特征,并对它们提供读、写操作。
事件:由类产生的通知,用于说明发生了什么事情。
索引器:允许编程人员在访问数组时,通过索引器访问类的多个实例。又称下标指示器。
运算符:定义类的实例能使用的运算符。
构造函数:在类被实例化时首先执行的函数,主要是完成对象初始化操作。
析构函数:在对象被销毁之前最后执行的函数,主要是完成对象结束时的收尾操作。类成员的可访问性
在编写程序时,可以对类的成员使用不同的访问修饰符,从而定义它们的访问级别,即类成员的可访问性(Accessibility)。publicprivateprotectedinternalinternalprotectednew
(1)公共成员它通过在成员声明中加public修饰符来定义。“公共的”直觉意义是“无限制访问”,定义的成员可以在类的外部进行访问。(2)保护成员 保护成员通过在成员声明中使用protected修饰符来定义。为了方便派生类的访问,但又不希望其他无关类随意访问,这时就可以使用protected修饰符,将成员声明为保护的。(3)私有成员 私有成员通过在成员声明中使用private修饰符来定义。C#中的私有成员只有类中的成员可以访问,在类的外部是禁止直接访问私有成员的。这也是C#中成员声明的默认方式,即若在成员声明时没有使用任何访问修饰符,那么C#自动将它限定为私有成员。(4)内部成员 内部成员通过在成员声明中使用internal修饰符来定义。该成员只能被程序集中的代码访问,而程序集之外的代码无法访问。(5)保护内部成员 同一个程序集中的所有类,以及所有程序集中的子类都可以访问。(6)new
new关键字可以在派生类中隐藏基类的方法,也就说在使用派生类的方法是调用的方法是New关键字新定义出来的方法,而不是基类的方法。namespaceExample05Lib
{
publicclassClass1
{
internalStringstrInternal=null;
publicStringstrPublic;
internalprotectedStringstrInternalProtected=null;
}
}
Example05Lib项目的Class2类可以访问到Class1的strInternal成员,当然也可以访问到strInternalProtected成员,因为他们在同一个程序集里
Example05项目里的Class3类无法访问到Class1的strInternal成员,因为它们不在同一个程序集里。但却可以访问到strInternalProtected成员,因为Class3是Class1的继承类publicclassBaseC{publicintx;publicvoidInvoke(){}}publicclassDerivedC:BaseC{newpublicvoidInvoke(){}}
类的成员又可以分成静态成员和非静态成员。在声明成员时,如果在语句前加上static保留字,则该成员是静态成员,如果没有static保留字,则成员是非静态成员。二者最重要的区别是:静态成员属于类所有,非静态成员属于类的实例所有,所以又称实例成员。
类的静态成员和实例成员7.1.3类的构造函数和析构函数
1.构造函数构造函数主要用来为对象分配存储空间,完成初始化操作(如给类的成员变量赋值等)。在C#中,类的构造函数遵循以下规定。(1)构造函数的函数名和类的名称一样。(2)当某个类没有构造函数时,系统将自动为其创建构造函数,这种构造函数称为默认构造函数。如例7-2中默认的构造函数为:
Example1(){};
(3)构造函数的访问修饰符总是public。如果是private,则表示这个类不能被实例化,这通常用于只含有静态成员的类中。(4)构造函数由于不需要显式调用,因而不用声明返回类型。(5)构造函数可以带参数也可以不带参数。
2.析构函数析构函数在对象销毁时被调用,常用来释放对象占用的存储空间。析构函数具有以下特点。(1)析构函数不能带有参数。(2)析构函数不能拥有访问修饰符。
(3)不能显式地调用析构函数。(4)析构函数的命名规则是在类名前加上一个“~”号。如上例的Example1类的析构函数为:
~Example1(){};(5)析构函数在对象销毁时自动调用。【例7-3】类的构造函数和析构函数的演示。(程序代码详见例7-3)[执行结果]
usingSystem;classExam{staticpublicinta;//静态成员
publicintb;//实例成员
publicExam()//构造函数,没有参数,用来给成员变量赋初值0{a=0;b=0;}publicExam(intm,intn)//构造函数,有参数,用来给成员变量赋特定的初值
{a=m;b=n;}~Exam()//析构函数
{}}classA_7_3{publicstaticvoidMain(){ExamE1=newExam();//产生类的实例E1,自动调用无参数的构造函数
Console.WriteLine("a={0},b={1}",Exam.a,E1.b);ExamE2=newExam(10,20);//产生类的实例E2,自动调用有参数的构造函数
Console.WriteLine("a={0},b={1}",Exam.a,E2.b);}}7.1.4类的方法及方法的重载
1.方法的定义
[格式]:[方法修饰符]返回值类型方法名([参数列表]){方法实现部分;}2.静态方法和非静态方法对于静态方法和非静态方法,只需抓住以下几点:(1)静态方法属于类所有,非静态方法属于类定义的对象所有;(2)非静态方法可以访问类中包括静态成员在内的所有成员,而静态方法只能访问类中的静态成员。【例7-4】静态方法和动态方法的演示。请观察并分析下列程序的执行结果。(程序代码详见例7-4)[执行结果]
3.方法的参数(1).值参数(没有修饰符)当使用值类型的参数调用方法时,编译程序将实参的值做一份副本,并且把此副本传递给该方法的相应形参。被调用的方法不会修改内存中实参的值,所以使用值参数时,可以保证实参值是安全的。定义含有值类型参数方法的格式:
[修饰符]返回的数据类型方法名(参数列表)方法的参数【例】下面的程序演示了当方法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;x=z;z=tmp;} if(y>z){tmp=y;y=z;z=tmp;} }}classTest{staticvoidMain(){ Myclassm=newMyclass(); inta,b,c; a=30;b=20;c=10; m.Sort(a,b,c); Console.WriteLine("a={0},b={1},c={2}",a,b,c); Console.Read();}}运行结果如图3.13所示:图3.13方法的值参数传递的运行结果(2).引用参数(ref)值类型参数传递的是实参值的副本,而引用型参数向方法传递的是实参的地址。在C#中,调用带引用型参数的方法就可以在该方法的内部改变调用方法的实参数值了。带引用型参数的方法头格式:
[修饰符]返回的数据类型方法名(参数列表)
传递的参数格式:
ref参数的数据类型参数名从格式上看,与值传递不同的是在引用型参数的数据类型前加ref关键字。定义和调用引用型参数的方法时,在形参和实参前都必须加上ref关键字。默认情况下,基本数据类型为值类型,这意味着定义一个变量时,系统会从内存中分配特定的单元。而像类等类型默认为引用类型,这意味着类名包含的是类数据的存储地址,而不是数据本身。方法的参数【例】程序中Sort方法的值参数传递方式改成引用参数传递,这样在方法Sort中对参数x、y、z按从小到大的排序影响了调用它的实参a、b、c。usingSystem;classMyclass{publicvoidSort(refintx,refinty,refintz) { inttmp;//tmp是方法Sort的局部变量
//将x,y,z按从小到大排序
if(x>y){tmp=x;x=y;y=tmp;} if(x>z){tmp=x;x=z;z=tmp;} if(y>z){tmp=y;y=z;z=tmp;} }}classTest{staticvoidMain(){ Myclassm=newMyclass(); inta,b,c; a=30;b=20;c=10; m.Sort(refa,refb,refc); Console.WriteLine("a={0},b={1},c={2}",a,b,c); Console.Read();}}运行结果如图所示:图3.13方法的值参数传递的运行结果(3).输出参数(out)C#还提供了一种特殊的参数传递方式,专门用于从方法返回数据,完成这种数据传递方式的输出型参数,用关键字out表示。与引用型参数相似,输出型参数也不另外开辟新的内存区域。它与引用型参数的差别在于:调用带有out关键字参数的方法之前,不需要对传递给形参的实参值进行初始化。但是,在将实参作为输出型参数传递的调用完成之后,该实参变量将会被方法中的形参明确赋值,并将数据从方法中传出至调用处。在定义和调用输出型参数的方法时,在形参和实参前都必须加上out关键字。
【例】在下面程序中,求一个数组元素中的最大值、最小值以及平均值。希望得到三个返回值,显然用方法的返回值不能解决,而且这三个值必须通过计算得到,初始值没有意义,所以解决方案可以定义三个out参数。usingSystem;classMyclass{
publicvoidMaxMinArray(int[]a,outintmax,outintmin,outdoubleavg) { intsum; sum=max=min=a[0]; for(inti=1;i<a.Length;i++) { if(a[i]>max)max=a[i]; if(a[i]<min)min=a[i]; sum+=a[i]; }avg=sum/a.Length; }}classTest{ staticvoidMain() { Myclassm=newMyclass(); int[]score={87,89,56,90,100,75,64,45,80,84}; intsmax,smin; doublesavg; m.MaxMinArray(score,outsmax,outsmin,outsavg); Console.Write("Max={0},Min={1},Avg={2}",smax,smin,savg); Console.Read(); }}运行结果如图所示。ref和out参数的使用并不局限于值类型参数,它们也可用于引用类型来传递对象。【例】下面程序定义了两个方法,一个是Swap1,一个是Swap2,它们都有两个引用对象作参数,但Swap2的参数加了ref修饰,调用这两个方法产生的结果是不一样的。usingSystem;classMyclass{
publicvoidSwap1(strings,stringt) { stringtmp; tmp=s; s=t; t=tmp; } publicvoidSwap2(refstrings,refstringt) { stringtmp; tmp=s; s=t; t=tmp; }}classTest{ staticvoidMain() { Myclassm=newMyclass(); strings1="ABCDEFG",s2="134567"; m.Swap1(s1,s2); Console.WriteLine("s1={0}",s1);//s1,s2的引用并没有改变
Console.WriteLine("s2={0}",s2); m.Swap2(refs1,refs2); //s1,s2的引用互相交换了
Console.WriteLine("s1={0}",s1); Console.WriteLine("s2={0}",s2); Console.Read(); }}运行结果如图所示。(4).参数数组当方法的参数前带有params关键字,这就是一个带参数数组的方法。在方法的参数列表中使用params关键字,可用于表示方法的形参个数不确定,这样可以在使用方法的过程中改变传入方法实参的个数。关于参数数组,需掌握以下几点。(1)若形参表中含一个参数数组,则该参数数组必须位于形参列表的最后;(2)参数数组必须是一维数组;(3)不允许将params修饰符与ref和out修饰符组合起来使用;(4)与参数数组对应的实参可以是同一类型的数组名,也可以是任意多个与该数组的元素属于同一类型的变量;(5)若实参是数组则按引用传递,若实参是变量或表达式则按值传递。
【例7-5】参数数组的演示。请观察并分析下列程序的执行结果。
(程序代码详见例7-5)
[执行结果]
4.方法的重载
方法重载是指同样的一个方法名,有多种不同的实现方法。方法重载的格式是在一个类中两次或多次定义同名的方法,这些同名的方法包括从基类继承而来的方法,这些方法名称相同,但每个方法的参数类型或个数不同,从而便于在用户调用方法时系统能够自动识别应调用的方法。这就是编译时的多态性。
【例7-6】方法重载的演示。请观察并分析下列程序的执行结果。(程序代码详见例7-6)[执行结果]
5.方法的覆盖
在一个有继承关系的类层次结构中,类中的方法由两部分组成:一个是类体中声明的方法,另一个则是直接从它的基类继承而来的方法。但派生类很少会一成不变地继承基类中所有方法,如果需要对基类的方法做出修改,就要在派生类中对基类方法进行覆盖。1)采用new关键字修饰派生类中与基类同名的方法。
【例】方法覆盖的演示。请观察并分析下列程序的执行结果。(程序代码详见覆盖举例fugai1)
从例中可以看出,使用关键字new修饰方法,可以在一个继承的结构中隐藏有相同签名的方法。但是正如程序中演示的基类对象A被引用到派生类对象B时,它访问的仍是基类的方法。更多的时候,我们期望根据当前所引用的对象来判断调用哪一个方法,这个判断过程是在运行时进行的。5.方法的覆盖
2)首先建基类的方法用关键字virtual修饰为虚方法,再由派生类用关键字override修饰与基类中虚方法具有相同签名的方法,标明是对基类的虚方法重载。这就是运行时的多态性。【例】将上例改写,在Shape类中方法area用virtual修饰,而派生类Triangle和Trapezia用关键字override修饰area方法,这样就可以在程序运行时决定调用哪个类的area方法。程序代码详见覆盖举例fugai2具体使用过程应注意以下几点:(1)不能将虚方法声明为静态的,因为多态性是针对对象的,不是针对类的。不能将虚方法声明为私有的,因为私有方法不能被派生类覆盖。(3)覆盖方法必须与它相关的虚方法匹配,也就是说,它们的方法签名(方法名称、参数个数、参数类型)、返回类型以及访问属性等都应该完全一致。(4)一个覆盖方法覆盖的必须是虚方法,但它本身又是一个隐式的虚方法,所以它的派生类还可以覆盖这个方法。不过尽管如此还是不能将一个覆盖方法显式地声明为虚方法。7.1.5运算符重载
在C#中,运算符重载在类中进行声明,声明的格式如下。[格式]:返回值类型operator运算符(运算对象列表) {
重载的实现部分; };在C#中,可以重载的运算符主要有:+-!~++--truefalse*/%&|^<<>>==!=<><=>=不能重载的运算符有:.=&&||?:newtypeofsizeofis【例7-7】运算符重载的演示。请观察并分析下列程序的执行结果。
(程序代码详见例7-7)
[执行结果]
7.1.9多态性
多态性是指同一操作作用于不同类的实例,这些类对它进行不同的解释,从而产生不同的执行结果的现象。在C#中有两种多态性:编译时的多态性和运行时的多态性。运行时的多态性是通过继承和虚成员来实现的。运行时的多态性是指系统在编译时不确定选用哪个重载方法,而是直到程序运行时,才根据实际情况决定采用哪个重载方法。编译时的多态性具有运行速度快的特点,通过方法重载实现,而运行时的多态性则具有极大的灵活性。运行时的多态性
如果希望基类中某个方法能够在派生类中进一步得到改进,那么可以把这个方法在基类中定义为虚方法。类中的方法前加上了virtual修饰符成为虚方法,反之为非虚方法。使用了virtual修饰符后不允许再有static,abstract或override修饰符。普通方法重载要求方法名称相同,参数类型和参数个数不同,而虚方法重载要求方法名称、返回值类型、参数表中的参数个数、类型顺序都必须与基类中的虚函数完全一致。在派生类中声明对虚方法的重载要求在声明中加上override关键字,而不能有new、static或virtual修饰符。【例7-11】虚函数与多态性的演示。请观察并分析下列程序的执行结果。(程序代码详见例7-11)[执行结果]
usingSystem;classBaseClass//基类{publicvoidNVMeth()//定义基类的非虚方法
{Console.WriteLine("调用了基类BaseClass类的非虚方法NVMeth");}publicvirtualvoidVMeth()//定义基类的虚方法
{Console.WriteLine("调用了基类BaseClass类的虚方法NMeth");}}classInClass:BaseClass//定义派生类{newpublicvoidNVMeth()//定义派生类的非虚方法,用new关闭警告
{Console.WriteLine("调用了派生类InClass类的非虚方法NVMeth");}publicoverridevoidVMeth()//定义派生类的虚方法,使用override进行重载
{Console.WriteLine("调用了派生类InClass类的虚方法NMeth");}}classTest{publicstaticvoidMain(){InClassInObj=newInClass();//生成派生类对象InObjBaseClassBaseObj=InObj;//把派生类InObj的对象赋值给基类的对象BaseObjBaseObj.NVMeth();//调用BaseClass类
BaseObj.VMeth();//调用InClassInObj.NVMeth();//调用InClassInObj.VMeth();//调用InClassBaseClassBaseObj1=newBaseClass();BaseObj1.NVMeth();//调用BaseClass类
BaseObj1.VMeth();//调用BaseClass
}}7.1.6域、属性和索引器
1.域域又称字段,它是类的一个成员,这个成员代表与对象或类相关的变量。域的定义格式如下。[格式]:[域修饰符]域类型域名;【例7-8】域的演示。请观察并分析下列程序的执行结果。(程序代码详见例7-8)[执行结果]
2.属性
属性是对现实世界中实体特征的抽象,它提供了一种对类或对象特性进行访问的机制。属性的声明格式如下。[格式]:[属性修饰符]类型说明符属性名{访问声明}
【例7-9】属性的演示。请观察并分析下列程序的执行结果。(程序代码详见例7-9)[执行结果]
3索引器使用索引器的目的是为了能够像数组一样访问类中的数组型的对象。通过对对象元素的下标的索引,就可以访问指定的对象。索引器类似于属性,也是使用get关键字和set关键字定义了对被索引元素的读写权限,它们之间不同的是索引器有索引参数。【例】索引器示例。usingSystem;classMyClass{ privatestring[]data=newstring[5]; //索引器定义,根据下标访问data publicstringthis[intindex] { get { returndata[index]; } set { data[index]=value; } }}classMyClient{ publicstaticvoidMain() { MyClassmc=newMyClass(); //调用索引器set赋值
mc[0]="Rajesh"; mc[1]="A3-126"; mc[2]="Snehadara"; mc[3]="Irla"; mc[4]="Mumbai";//调用索引器get读出
Console.WriteLine("{0},{1},{2},{3},{4}",mc[0],mc[1],mc[2],mc[3],mc[4]); }}
运行结果如下:
Rajesh,A3-126,Snehadara,Irla,Mumbai索引器的get和set中可以增加各种计算和控制代码。7.1.7this关键字
this关键字用来引用类的当前实例,成员通过this关键字可以知道自己属于哪一个实例。this关键字只能用在类的构造函数、类的实例方法中,在其它地方(如静态方法中)使用this关键字均是错误的。以下是this的常用用途。(1)限定被相似的名称隐含的成员,例如:classc1{privatestringname;publicEmployee(stringname,stirngalias){=name;this.alias=alias;}}(2)将对象作为参数传递到其他方法,例如:CalcTax(this);(3)声明索引器,例如:publicintthis[intindex]{get{returnarray[index];}set{array[index]=value;}}事件事件作为C#中的一种类型,为类和类的实例定义发出通知的能力,从而将事件和可执行代码捆绑在了一起。事件最常见的用途是用于窗体编程,当发生像点击按钮、移动鼠标等事件时,相应的程序将收到通知,再执行代码。
C#事件是按“发布-预订”的方式工作。先在一个类中公布事件,然后就可以在任意数量的类中对事件预订。事件的工作过程可以用图4.12表示:图4.12事件的工作图事件C#事件机制是基于委托实现的,因此要首先定义一个委托EventHandler:
publicdelegatevoidEventHandler(objectfrom,myEventArgse)System.EventArgs是包含事件数据的类的基类,在代码中可直接使用EventArgs类。myEventArgs类派生于EventArgs类,实现自定义事件数据的功能。这里from表示发生事件的对象。定义事件格式为:
event事件的委托名事件名如事件TextOut定义:
publiceventEventHandlerTextOut;事件的激活一般写成:
if(TextOut!=null)TextOut(this,newEventArgs());
检查TextOut事件有没有被订阅,如不为null,则表示有用户订阅。订阅事件的是TestApp类,首先实例化EventSource,然后订阅事件:
evsrc.TextOut+=newEventSource.EventHandler(CatchEvent);也可以取消订阅:
evsrc.TextOut-=newEventSource.EventHandler(CatchEvent);事件【例】事件示例。usingSystem;//定义事件包含数据publicclassMyEventArgs:EventArgs{ privatestringStrText; publicMyEventArgs(stringStrText) { this.StrText=StrText; } publicstringGetStrText { get { returnStrText; } }}【例】//发布事件的类classEventSource{ MyEventArgsEvArgs=newMyEventArgs("触发事件");//定义委托
publicdelegatevoidEventHandler(objectfrom,MyEventArgse);//定义事件
publiceventEventHandlerTextOut; //激活事件的方法
publicvoidTriggerEvent() { if(TextOut!=null) TextOut(this,EvArgs); }}【例】//订阅事件的类classTestApp{ publicstaticvoidMain() { EventSourceevsrc=newEventSource(); //订阅事件
evsrc.TextOut+=newEventSource.EventHandler(CatchEvent);//触发事件
evsrc.TriggerEvent(); Console.WriteLine("------");//取消订阅事件
evsrc.TextOut-=newEventSource.EventHandler(CatchEvent); //触发事件
evsrc.TriggerEvent(); //事件订阅已取消,什么也不执行【例】Console.WriteLine("------"); TestApptheApp=newTestApp(); evsrc.TextOut+=newEventSource.EventHandler(theApp.InstanceCatch); evsrc.TriggerEvent(); Console.WriteLine("------"); } //处理事件的静态方法
publicstaticvoidCatchEvent(objectfrom,MyEventArgse) { Console.WriteLine("CathcEvent:{0}",e.GetStrText); } //处理事件的方法
publicvoidInstanceCatch(objectfrom,MyEventArgse) { Console.WriteLine("InstanceCatch:{0}",e.GetStrText); }}【例】运行结果如图4.13所示。
EventHandler是一个委托声明如下
public
delegate
void
EventHandler(
object
sender
,
EventArgs
e
)
注意这里的参数,前者是一个对象(其实这里传递的是对象的引用,如果是button1的click事件则sender就是button1),后面是包含事件数据的类的基类。
下面我们研究一下Button类看看其中的事件声明(使用WinCV工具查看),以Click事件为例。
public
event
EventHandler
Click;
这里定义了一个EventHandler类型的事件Click
前面的内容都是C#在类库中已经为我们定义好了的。下面我们来看编程时产生的代码。
private
void
button1_Click(object
sender,
System.EventArgs
e)
{
...
}
这是我们和button1_click事件所对应的方法。注意方法的参数符合委托中的签名(既参数列表)。那我们怎么把这个方法和事件联系起来呢,请看下面的代码。
this.button1.Click
+=
new
System.EventHandler(this.button1_Click);
把this.button1_Click方法绑定到this.button1.Click事件。ButtonClick事件7.1.8类的继承
继承是面向对象程序设计中实现代码重用的重要机制之一,它起源于现实世界中事物之间的联系。类的继承的基本格式与功能如下。
[格式]:
class派生类类名:基类类名
{成员声明列表;}【例7-10】类继承的演示。请观察并分析下列程序的执行结果。(程序代码详见例7-10)
[执行结果]
抽象类
抽象类是基类的一种特殊类型。除了拥有普通的类成员之外,还有抽象类成员。抽象类成员中的方法和属性,只有声明(使用关键字abstract),而没有实现部分。由于对实例而言,没有实现的成员是不合法的,所以抽象类永远也不能实例化。这种不能实例化的类也有它的作用空间,它们可以在类层次结构的上层,对于派生于该类的其他类而言,抽象类就确定了子类的基本结构和意义,从而使程序框架更容易建立。抽象类
包含一个或多个抽象函数的类本身必须声明为abstract,但是,抽象类可以包含非抽象的成员。从抽象类派生的类必须对基类中包含的所有抽象方法提供实现过程,否则,它也为抽象类。抽象函数为隐式的虚函数,所以为继承的抽象类提供了实现代码的方式与覆盖一个虚方法相似。另外,属性和索引也可以声明为abstract。密封类
上面介绍的种种例子无不说明继承的作用显著,但有时候,我们并不希望自己编写的类被继承,或者已经认定没有必要继承了。于是,C#提出了密封类(sealedclass)的概念。类声明为密封后,就不能用来派生新的类。密封类
密封类具有不能用来继承的限制,但它也有自身的长处。一个类声明为密封的(sealed)有利于提高稳定性。因为,继承性是对基类的内部的某种程度的保护性访问。如果类是密封的,那么就完全避免了由派生类引起崩溃的可能性。同时,编译器也能针对密封类做相应的优化,例如,可以避免增加与虚拟方法相关联的系统总开销。
接口1.接口介绍接口是用来定义一种程序的协定。接口好比一种模版,这种模版定义了实现接口的对象必须实现的方法,其目的就是让这些方法可以作为接口实例被引用。接口的定义如:
publicinterfaceIPartA { voidSetDataA(stringdataA); }接口使用关键字interface定义,接口可以使用的修饰符包括new,public,protected,internal,private等。接口的命名通常是以I开头,如IPartA,IPartB。接口的成员可以是方法、属性、索引器和事件,但不可以有任何的成员变量,也不能在接口中实现接口成员。接口不能被实例化。接口的成员默认是公共的,因此不允许成员加上修饰符。【例】接口演示。usingSystem;//定义接口IPartApublicinterfaceIPartA{ voidSetDataA(stringdataA);}//定义接口IPartB,继承IPartApublicinterfaceIPartB:IPa
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 辽宁现代服务职业技术学院《生物学教学艺术与教学设计》2023-2024学年第一学期期末试卷
- 兰州工商学院《半导体器件制造及测试技术》2023-2024学年第一学期期末试卷
- 吉林艺术学院《结构稳定》2023-2024学年第一学期期末试卷
- 湖南税务高等专科学校《风景区规划与设计》2023-2024学年第一学期期末试卷
- 湖南电子科技职业学院《城市修建性详细规划》2023-2024学年第一学期期末试卷
- 黑龙江生态工程职业学院《园林植物生物技术》2023-2024学年第一学期期末试卷
- 重庆艺术工程职业学院《影视动画制作》2023-2024学年第一学期期末试卷
- 重庆机电职业技术大学《机器学习与模式识别II(双语)》2023-2024学年第一学期期末试卷
- 中央司法警官学院《建筑空间生活》2023-2024学年第一学期期末试卷
- 浙江农林大学《社区管理与服务》2023-2024学年第一学期期末试卷
- 派克比例阀中文说明书
- 高一学生心理素质描述【6篇】
- 给男友的道歉信10000字(十二篇)
- 2020年高级统计实务与案例分析真题及答案
- 全面质量管理(TQM)基本知识
- 练字本方格模板
- 产品供货质量保障措施
- 电力电缆高频局放试验报告
- JJG 517-2016出租汽车计价器
- JJF 1914-2021金相显微镜校准规范
- GB/T 32045-2015节能量测量和验证实施指南
评论
0/150
提交评论