C程序设计第8章.pptx
《C程序设计第8章.pptx》由会员分享,可在线阅读,更多相关《C程序设计第8章.pptx(43页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、#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()show();p=&b;/A类指针指向类指针指向B类对象类对象p-show();p=&c;/A类指针指向类指针指向C类对象类对象p-show();输出输出:A:display()A:display()A:display()解决办法:虚函数解决办法:虚函数第2页/共43页 如果一个派生类有多个直接基类
2、,而这些直接基类又如果一个派生类有多个直接基类,而这些直接基类又有一个共同的基类,则在最终的派生类中会保留该间接共有一个共同的基类,则在最终的派生类中会保留该间接共同基类数据成员的多份同名成员。同基类数据成员的多份同名成员。-二义性二义性解决办法:解决办法:定义虚基类,使得在继承间接共同基类时只保留一份定义虚基类,使得在继承间接共同基类时只保留一份成员。成员。为保证虚基类在派生类中只继承一次,应当在该基类为保证虚基类在派生类中只继承一次,应当在该基类的所有直接派生类中声明为虚基类。否则仍然会出现对的所有直接派生类中声明为虚基类。否则仍然会出现对基类的多次继承。基类的多次继承。声明虚基类格式:声
3、明虚基类格式:class 派生类名:派生类名:virtual 继承方式继承方式 基类名基类名第3页/共43页虚基类的初始化:虚基类的初始化: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);第4页/共43页注意:注意:1.1.前介绍,在派生类的构造函数中只需对其直接基类初始前介绍,在派生类的构造函数中只
4、需对其直接基类初始化,再由其直接基类负责对间接基类初始化。化,再由其直接基类负责对间接基类初始化。2.2.现在,由于虚基类在派生类中只有一份数据成员,所以现在,由于虚基类在派生类中只有一份数据成员,所以这份数据成员的初始化必须由派生类直接给出。这份数据成员的初始化必须由派生类直接给出。派生类不仅要负责对其直接基类初始化还要负责对虚派生类不仅要负责对其直接基类初始化还要负责对虚基类初始化。基类初始化。在派生类对象的在派生类对象的创建创建中:中:首先是虚基类的构造函数并按它们声明的顺序构造。首先是虚基类的构造函数并按它们声明的顺序构造。第二批是非虚基类的构造函数按它们声明的顺序调用。第二批是非虚基
5、类的构造函数按它们声明的顺序调用。第三批是成员对象的构造函数。第三批是成员对象的构造函数。最后是派生类自己的构造函数被调用。最后是派生类自己的构造函数被调用。构造函数执行次序:构造函数执行次序:析构的次序与构造的次序相反。析构的次序与构造的次序相反。第5页/共43页例:例:通过构造函数的初始化表对虚基类进行初始化通过构造函数的初始化表对虚基类进行初始化。#include class A /定义基类定义基类A Apublic:int x;A(int a=0)x=a;/基类构造函数,有一个参数基类构造函数,有一个参数A()coutA析构析构endl;class B:virtual public A
6、 /A/A作为作为B B的虚基类的虚基类public:int y;B(int a=0,int b=0):A(b)y=a;/B/B类构造函数,在初始化表中对虚基类初始化类构造函数,在初始化表中对虚基类初始化B()coutB析构析构endl;void PB()coutx=xty=yendl;第6页/共43页class C:virtual public A /A/A作为作为C C的虚基类的虚基类public:int z;C(int a=0,int b=0):A(b)z=a;/C/C类构造函数,在初始化表中对虚基类初始化类构造函数,在初始化表中对虚基类初始化C()coutC析构析构endl;void
7、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()如果在虚基类中定义了带参数的构造函数,则在其所有如果在虚基类中定义了带参数的构造函数,则在其所有派生类中(包括直接派生或间接派生的派生类)中,通派生类中(包括直接派生或间接派生的派生类)中,通过构造函数的初始化表对虚基类进行初始化。过构造函数的初始化表对虚基类进行初始化。第7
8、页/共43页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(
9、d,e)m=f;第8页/共43页8.7 8.7 多态性与虚函数多态性与虚函数多态性是面向对象程序设计的关键技术之一。指的是多态性是面向对象程序设计的关键技术之一。指的是调用同样的函数实现不同的功能。调用同样的函数实现不同的功能。在在C+中中有两种多有两种多态态编译时的编译时的多态性多态性 (静态多态性)(静态多态性)运行时的多态运行时的多态性性 在程序执行前无法确定调用哪一个函数,必在程序执行前无法确定调用哪一个函数,必须在程序执行过程中,根据执行的具体情况须在程序执行过程中,根据执行的具体情况来动态地确定。来动态地确定。通过类继承关系和虚函数来通过类继承关系和虚函数来实现的。目的:建立一种通
10、用的程序。实现的。目的:建立一种通用的程序。通过函数的重载和运算符的重通过函数的重载和运算符的重载实现。载实现。多态性是多态性是“一个接口,多种方法一个接口,多种方法”:通过继承产生了相关的不同的派生类,和基类成员同通过继承产生了相关的不同的派生类,和基类成员同名的成员在不同的派生类中有不同的含义。名的成员在不同的派生类中有不同的含义。第9页/共43页虚函数的作用虚函数的作用:允许在派生类中重新定义与基类同名的函数,并且允许在派生类中重新定义与基类同名的函数,并且可以通过基类指针或引用来访问基类和派生类中的同名可以通过基类指针或引用来访问基类和派生类中的同名函数。函数。虚函数是一个类的成员函数
11、,定义虚函数的格式如下:虚函数是一个类的成员函数,定义虚函数的格式如下:virtual 返回类型返回类型 函数名(参数表);函数名(参数表);注:注:virtual仅用于类定义中,若虚函数在类外定义,不能仅用于类定义中,若虚函数在类外定义,不能 加加virtual(类中函数说明要加类中函数说明要加virtual)。当某一个类的一个类成员函数被定义为虚函数,则由当某一个类的一个类成员函数被定义为虚函数,则由该类派生出来的所有派生类中,该函数始终保持虚函数的该类派生出来的所有派生类中,该函数始终保持虚函数的特征。特征。8.7.1 8.7.1 虚函数的定义虚函数的定义在派生类中重新定义虚函数在派生类
12、中重新定义虚函数(称称超载超载或或覆盖覆盖)时,不必再加关键字时,不必再加关键字virtual,但,但函数头一函数头一定要完全相同定要完全相同。第10页/共43页虚函数的使用虚函数的使用:(1)在基类用在基类用virtual声明成员函数为虚函数。声明成员函数为虚函数。(2)在派生类中重新定义此函数,要求函数名、函数类型、在派生类中重新定义此函数,要求函数名、函数类型、函数参数个数和类型全部与基类的虚函数相同,并根据函数参数个数和类型全部与基类的虚函数相同,并根据派生类的需要重新定义函数体。派生类的需要重新定义函数体。(3)定义一个指向基类对象的指针变量,并使它指向同一定义一个指向基类对象的指针
13、变量,并使它指向同一类族中需要调用该函数的对象。类族中需要调用该函数的对象。(4)通过该指针变量调用此虚函数,此时调用的就是指针通过该指针变量调用此虚函数,此时调用的就是指针变量指向的对象的同名函数。变量指向的对象的同名函数。第11页/共43页例:例:#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()show(
14、);/动态调用动态调用p=&b1;p-show();/动态调用动态调用 p=&c1;p-show();/动态调用动态调用运行结果运行结果:A:show()B:show()C:show()void main()C c;c.A:show();/静态调用静态调用c.B:show();/静态调用静态调用 c.show();/静态调用静态调用第13页/共43页【例例8.6】计算学分。计算学分。由本科生类派生出研究生类由本科生类派生出研究生类GradeStudent,但它们各自,但它们各自的从课程学时数折算为学分数的算法是不同的,本科生是的从课程学时数折算为学分数的算法是不同的,本科生是1616个学时个学
15、时一学分,而研究生是一学分,而研究生是2020个学时一学分。个学时一学分。class Studentchar coursename20;/课程名课程名int classhour;/学时学时int credit;/学分学分,未考虑未考虑0.50.5学分学分public:Student();/构造函数,将类成员赋值为构造函数,将类成员赋值为0 0void Calculate();/计算学分(考虑该函数的设置)计算学分(考虑该函数的设置)void SetCourse(char*str,int hour);/设置课程和学时设置课程和学时int GetHour();/获取学时数获取学时数void Set
16、Credit(int cred);/获取学分获取学分void Print();/显示学时和学分显示学时和学分;第14页/共43页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(coursenam
17、e,str);classhour=hour;第15页/共43页 int GetHour()return classhour;/获取学时数获取学时数 void SetCredit(int cred)credit=cred;/获取学分获取学分 voidPrint()/显示学时和学分显示学时和学分 coutcoursenametclasshour学时学时 tcredit学分学分endl;class GradeStudent:public Studentpublic:GradeStudent();/基类缺省构造函数调用可省基类缺省构造函数调用可省 void Calculate()SetCredit(G
18、etHour()/20);第16页/共43页void main()Student s,*ps;GradeStudent g;s.SetCourse(物理物理,80);s.Calculate();g.SetCourse(物理物理,80);g.Calculate();cout本科生本科生:t;s.Print();cout“研究生研究生:Calculate();cout本科生本科生:Print();ps=&g;ps-Calculate();cout研究生研究生:Print();输出结果为输出结果为:本科生:物理本科生:物理 80 学时学时 5学分学分研究生:物理研究生:物理 80 学时学时 4学分学
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 程序设计
限制150内