欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    C程序设计第8章1.ppt

    • 资源ID:5336454       资源大小:206.01KB        全文页数:44页
    • 资源格式: PPT        下载积分:10金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要10金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    C程序设计第8章1.ppt

    本周习题:P307 习题8.6 实践教程:P89 实验二十四 2本周实验:习题上机调试 预习:第9章流类库与输入/输出 9.19.3(1)理解C+的基本流类体系;(2)提高标准输入/输出的健壮性;(3)掌握提取与插入运算符的重载(4)掌握文件的输入/输出:文件的打开与关闭,文本 文件与二进制文件。(5)掌握在构造函数中通过文件建立对象,在析构函数 中由文件保存对象的技术。,类似用实型变量描述整数,这条规则称赋值兼容规则。赋值兼容包括以下三种情况:,派生类与基类(赋值兼容),1.派生类对象赋值给基类的对象。反之不行。如:Person p;Student s;p=s;,2.派生类对象的地址赋给基类指针。反之不行。如:Person*pointP;pointP=,3.派生类对象可以初始化基类的引用。反之不行。如:Person 常见用法是函数形参为基类引用,实参是派生类对象,注意:以上赋值后都只能间接使用到继承来的成员。,#include class A public:void show()coutA:show()endl;class B:public A public:void show()coutB:show()endl;class C:public Bpublic:void show()coutC:show()endl;,void main()A a;/声明A类对象B b;/声明B类对象C c;/声明C类对象A*p;/声明A类指针p=,输出:A:display()A:display()A:display(),解决办法:虚函数,如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员。-二义性,解决办法:定义虚基类,使得在继承间接共同基类时只保留一份成员。,为保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。否则仍然会出现对基类的多次继承。,声明虚基类格式:class 派生类名:virtual 继承方式 基类名,虚基类的初始化:class A public:A(int i);class B:virtual public A public:B(int n):A(n);class C:virtual public A public:C(int n):A(n);class D:public B,public C public:D(int n):A(n),B(n),C(n);,注意:前介绍,在派生类的构造函数中只需对其直接基类初始化,再由其直接基类负责对间接基类初始化。,2.现在,由于虚基类在派生类中只有一份数据成员,所以这份数据成员的初始化必须由派生类直接给出。,派生类不仅要负责对其直接基类初始化还要负责对虚基类初始化。,在派生类对象的创建中:首先是虚基类的构造函数并按它们声明的顺序构造。第二批是非虚基类的构造函数按它们声明的顺序调用。第三批是成员对象的构造函数。最后是派生类自己的构造函数被调用。,构造函数执行次序:,析构的次序与构造的次序相反。,例:通过构造函数的初始化表对虚基类进行初始化。#include class A/定义基类Apublic:int x;A(int a=0)x=a;/基类构造函数,有一个参数A()coutA析构endl;class B:virtual public A/A作为B的虚基类public:int y;B(int a=0,int b=0):A(b)y=a;/B类构造函数,在初始化表中对虚基类初始化B()coutB析构endl;void PB()coutx=xty=yendl;,class C:virtual public A/A作为C的虚基类public:int z;C(int a=0,int b=0):A(b)z=a;/C类构造函数,在初始化表中对虚基类初始化C()coutC析构endl;void PC()coutx=xtz=zendl;class D:public B,public Cpublic:int m;D(int a,int b,int d,int e,int f):B(a,b),C(d,e)m=f;D()coutD析构endl;void Print()PB();PC();coutm=mendl;,A(),如果在虚基类中定义了带参数的构造函数,则在其所有派生类中(包括直接派生或间接派生的派生类)中,通过构造函数的初始化表对虚基类进行初始化。,void main()D d1(100,200,300,400,500);d1.Print();d1.x=400;d1.Print();,输出:x=0 y=100/基类构造函数使用了默认值做参数x=0 z=300/基类构造函数使用了默认值做参数m=500 x=400 y=100/主函数改变了基类参数值x=400 z=300/主函数改变了基类参数值m=500D析构C析构B析构A析构,D(int a,int b,int d,int e,int f):A(),B(a,b),C(d,e)m=f;,8.7 多态性与虚函数,多态性是面向对象程序设计的关键技术之一。指的是调用同样的函数实现不同的功能。,在C+中有两种多态,编译时的多态性(静态多态性),运行时的多态性,在程序执行前无法确定调用哪一个函数,必须在程序执行过程中,根据执行的具体情况来动态地确定。通过类继承关系和虚函数来实现的。目的:建立一种通用的程序。,通过函数的重载和运算符的重载实现。,多态性是“一个接口,多种方法”:通过继承产生了相关的不同的派生类,和基类成员同名的成员在不同的派生类中有不同的含义。,虚函数的作用:允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名函数。,虚函数是一个类的成员函数,定义虚函数的格式如下:virtual 返回类型 函数名(参数表);,注:virtual仅用于类定义中,若虚函数在类外定义,不能 加virtual(类中函数说明要加virtual)。,当某一个类的一个类成员函数被定义为虚函数,则由该类派生出来的所有派生类中,该函数始终保持虚函数的特征。,8.7.1 虚函数的定义,在派生类中重新定义虚函数(称超载或覆盖)时,不必再加关键字virtual,但函数头一定要完全相同。,虚函数的使用:(1)在基类用virtual声明成员函数为虚函数。,(2)在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。,(3)定义一个指向基类对象的指针变量,并使它指向同一类族中需要调用该函数的对象。,(4)通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。,例:#includeclass Apublic:virtual void show();void A:show()coutA:show()endl;class B:public Apublic:void show()coutB:show()endl;class C:public Bpublic:void show()coutC:show()endl;,void main()A a1,*p;B b1;C c1;p=/动态调用,运行结果:A:show()B:show()C:show(),void main()C c;c.A:show();/静态调用c.B:show();/静态调用 c.show();/静态调用,【例8.6】计算学分。由本科生类派生出研究生类GradeStudent,但它们各自的从课程学时数折算为学分数的算法是不同的,本科生是16个学时一学分,而研究生是20个学时一学分。class Studentchar coursename20;/课程名int classhour;/学时int credit;/学分,未考虑0.5学分public:Student();/构造函数,将类成员赋值为0void Calculate();/计算学分(考虑该函数的设置)void SetCourse(char*str,int hour);/设置课程和学时int GetHour();/获取学时数void SetCredit(int cred);/获取学分void Print();/显示学时和学分;,class Student char coursename20;/课程名 int classhour;/学时 int credit;/学分public:Student()coursename0=0;classhour=0;credit=0;virtual void Calculate()credit=classhour/16;void SetCourse(char*str,int hour)/设置课程和学时 strcpy(coursename,str);classhour=hour;,int GetHour()return classhour;/获取学时数 void SetCredit(int cred)credit=cred;/获取学分 voidPrint()/显示学时和学分 coutcoursenametclasshour学时 tcredit学分endl;,class GradeStudent:public Studentpublic:GradeStudent();/基类缺省构造函数调用可省 void Calculate()SetCredit(GetHour()/20);,void main()Student s,*ps;GradeStudent g;s.SetCourse(物理,80);s.Calculate();g.SetCourse(物理,80);g.Calculate();cout本科生:t;s.Print();cout“研究生:t;g.Print();s.SetCourse(“数学,160);,g.SetCourse(数学,160);ps=,输出结果为:本科生:物理 80 学时 5学分研究生:物理 80 学时 4学分本科生:数学 160学时 10学分研究生:数学 160学时 8学分,使用基类引用去指向不同对象,同样可实现运行时多态性。,void Calfun(Student,【例8.7】计算学分,基类与派生类定义同【例8.6】(基类派生类函数不变),增加函数:,几点提示:,5.虚函数重构不同于重载。派生类中定义虚函数必须与基类中的虚函数同名外,还必须同参数表,同返回类型。否则被认为是重载,而不是虚函数。,1.实现动态多态性需要三个条件:派生类体系、虚函数、指针或引用。,2.析构函数可定义为虚函数,构造函数不能定义虚函数。在基类及其派生类都有动态分配的内存空间时,应当考虑把析构函数定义为虚函数,以便能够用基类指针实现撤消对象的多态性。,3.虚函数执行速度稍慢。为了实现多态性,每一个派生类中均要保存相应虚函数的入口地址表,函数的调用机制也与一般函数不同。这是多态性为实现通用性付出的代价。,4.静态成员函数不能作为虚函数,因为它不属于某个对象,而是为所有同类对象共有。内联函数也不能作为虚函数。,声明虚函数的成员函数主要考虑以下几点:,首先看成员函数所在的类是否会作为基类。然后看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该将它声明为虚函数。,(2)如果成员函数在类被继承后功能不需修改,或派生类用不到该函数,则不要把它声明为虚函数。,(3)应考虑对成员函数的调用是通过对象名还是通过基类指针或引用去访问,如果是通过基类指针或引用去访问的,则应当声明为虚函数。,虚析构函数,析构函数的作用:在对象撤销之前做必要的“清理现场”的工作。当派生类的对象从内存中撤销时一般先调用派生类的析构函数,然后再调用基类的析构函数。,如果用new运算符建立了临时对象,若基类中有析构函数,并且定义了一个指向该基类的指针变量。在程序用带指针参数的delete运算符撤销对象时,会出现:系统会只执行基类的析构函数,而不执行派生类的析构函数。,解决办法:把析构函数定义为虚函数,实现撤消对象时的多态性。,虚析构函数声明:virtual 类名();,#includeclass A public:A()coutA析构n;class B:public A public:B();B();private:int*p;,B:B()p=new int();B:B()coutB析构n;delete p;void fun(A*a)delete a;void main()A*a=new B;/a是指向基类的指针变量指向new开辟的动态存储空间 fun(a);,输出:A析构,virtual,输出:B析构 A析构,把基类的析构函数声明为虚函数。可使所有派生类的析构函数自动成为虚函数(即使函数名不同)。若程序中显式地用了delete运算符准备删除一个对象,而delete运算符的操作对象用了指向派生类对象的基类指针,系统会调用相应类的析构函数。,1.虚函数是动态关联的基础。,2.虚函数是非静态的成员函数。,3.virtual 只用来说明类声明中的原型,不能用在函数实 现时。,4.具有继承性,基类中声明了虚函数,派生类中无论是 否说明,同原型函数都自动为虚函数。,5.不是重载声明而是覆盖。,6.通过基类指针或引用,执行时会根据指针指向的对象的类,决定调用哪个函数。,【例8.5_1】把【例8.1】析构函数改造为虚函数。,一般为了将类设计成通用的,必须把析构函数定义为虚函数。在动态分配内存时所有C+的标准库函数都采用这种格式。,class Person/数据成员略public:virtual Person();/其他成员函数略;,在主函数中添加以下内容:Person*per4;Student*stu4=new Student;*stu4=stu1;/把stu1的数据拷入*stu4 stu4-PrintStudentInfo();per4=stu4;delete per4;/基类指针撤销派生类对象,必须显式撤销,例:,class Pointpublic:.double Area()return 0;.;,class Circle:public Pointpublic:double Area()return PI*radius*radius;,基类函数为空或可以不要,在实现部分仍然要写出函数体,纯虚函数可以解决接口,8.7.2 纯虚函数,1.纯虚函数不同于空函数,纯虚函数不能调用。2.派生类中必须重新定义纯虚函数的函数体。,纯虚函数(pure virtual function)当基类中某虚函数无法具体实现,可定义为纯虚函数,具体实现依赖于派生类。定义格式为:,定义纯虚函数要注意:,virtual 返回类型 函数名(参数表)=0;,含有纯虚函数的基类不能用来定义对象,称为抽象类。抽象类的意义在于定义框架。,注:纯虚函数没有函数体;最后面的“=0”并不表示函数返回值为0,它只起形式 上的作用,告诉编译系统“这是纯虚函数”;这是一个声明语句,最后应有分号。,含有纯虚函数的基类是不能用来定义对象的。纯虚函数没有实现部分,不能产生对象,含有纯虚函数的类是抽象类。,抽象类,带有纯虚函数的类称为抽象类:class 类名 virtual 类型 函数名(参数表)=0;/纯虚函数.,作用:抽象类为抽象和设计的目的而建立,将有关的数据和 行为组织在一个继承层次结构中,保证派生类具有要 求的行为。,对于暂时无法实现的函数,可以声明为纯虚函数,留 给派生类去实现。,注意,抽象类只能作为基类来使用。不能声明抽象类的对象。构造函数不能是虚函数,析构函数可以是虚函数。,#include class B0/抽象基类B0声明public:/外部接口virtual void display()=0;/纯虚函数成员;class B1:public B0/公有派生public:void display()/虚成员函数 coutB1:display()endl;,class D1:public B1/公有派生public:void display()/虚成员函数 coutdisplay();,void main()B0*p;/声明抽象基类指针B1 b1;/声明派生类对象D1 d1;/声明派生类对象p=/调用派生类D1函数成员,程序的运行结果为:B1:display()D1:display(),结论:一个基类如果包含一个或一个以上纯虚函数,就是抽 象基类。,(2)派生类如果没有实现基类中的全部纯虚函数,则该派 生类仍然是抽象类;,(3)在类的层次结构中,顶层或最上面的几层可以是抽象 基类。抽象基类体现了本类族中各类的共性,把各类 中共有的成员函数集中在抽象基类中声明。,(4)抽象基类是本类族的公共接口。,(5)区别静态关联和动态关联。通过对象调用虚函数静态关联 通过基类指针调用虚函数动态关联,(6)如果在基类声明了虚函数,则在派生类中凡是与该函 数有相同的函数名、函数类型、参数个数和类型的函 数,均为虚函数(不论在派生类中是否用virtual声明)。,把类的声明与类的使用分离。对于设计类库的软件开发商来说尤为重要。开发商设计了各种各样的类,但不向用户提供源代码,用户可以不知道类是怎样声明的,但是可以使用这些类来派生出自己的类。,(7)使用虚函数提高了程序的可扩充性。,class Person int MarkAchieve;/业绩分 char Name20;public:Person(char*name)strcpy(Name,name);MarkAchieve=0;void SetMark(int mark)MarkAchieve=mark;virtual void CalMark()=0;void Print()coutName的业绩分为:MarkAchieveendl;,【例8.8】学校对在册人员进行奖励,依据是业绩分。业绩分的计算方法只能对具体人员进行,各类人员算法不同,所以将在册人员类定义为抽象类,业绩计算方法为纯虚函数。,class Student:public Person int credit,grade;/学历和成绩public:Student(char*name,int cred,int grad):Person(name)credit=cred;grade=grad;void CalMark()SetMark(credit*grade);,class Teacher:public Person int classhour,studnum;/授课学时和学生人数public:Teacher(char*name,int ch,int sn):Person(name)classhour=ch;studnum=sn;void CalMark()int K=(studnum+15)/30;/工作量系数,30人一班,15人以下不开课 switch(K)case 1:SetMark(classhour*studnum);break;case 2:SetMark(classhour*(30+(studnum-30)*8/10);break;case 3:SetMark(classhour*(30+24+(studnum-60)*6/10);break;case 4:SetMark(classhour*(30+24+18+(studnum-90)*4/10);break;case 5:SetMark(classhour*(30+24+12+(studnum-120)*2/10);break;default:SetMark(classhour*(30+24+12+6+(studnum-150)*1/10);,int main()Person*pp;Student s1(张成,20,80);Teacher t1(范英明,64,125),t2(李凯,80,85);pp=,class Simpson double Intevalue,a,b;/Intevalue积分值,a积分下限,b积分上限public:virtual double fun(double x)=0;/被积函数声明为纯虚函数 Simpson(double ra=0,double rb=0)a=ra;b=rb;Intevalue=0;void Integrate()double dx;int i;dx=(b-a)/2000;Intevalue=fun(a)+fun(b);for(i=1;i2000;i+=2)Intevalue+=4*fun(a+dx*i);for(i=2;i2000;i+=2)Intevalue+=2*fun(a+dx*i);Intevalue*=dx/3;,【例8.9】用虚函数来实现辛普生法求函数的定积分。(P210 例6.11),void Print()cout积分值=Intevalueendl;在派生类中加被积函数:class A:public Simpsonpublic:A(double ra,double rb):Simpson(ra,rb);double fun(double x)return sin(x);class B:public Simpson/B也可以说明为由A派生,更利于说明动态多态性public:B(double ra,double rb):Simpson(ra,rb);double fun(double x)return exp(x);,int main()A a1(0.0,3.1415926535/2.0);Simpson*s=,

    注意事项

    本文(C程序设计第8章1.ppt)为本站会员(sccc)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开