《8C++第八章习题解答.docx》由会员分享,可在线阅读,更多相关《8C++第八章习题解答.docx(27页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第八章 继承与多态习题一. 基本概念与基础知识自测题8.1 填空题8.1.1 如果类继承了类,则类称为 (1) 类,而类称为 (2) 类。 (3) 类的对象可作为 (4) 类的对象处理,反过来不行,因为 (5) 。如果强制转换则要注意 (6) 。答案:(1)基类(2)派生类(3)派生类(4)基类(5)派生类有一些新成员(6)只能派生类强制转换为基类8.1.2 当用public继承从基类派生一个类时,基类的public成员成为派生类的 (1) 成员,protected成员成为派生类的 (2) 成员,对private成员是 (3) 。公有派生可以使其类的 (4) ,所以公有派生是主流。答案:(1)
2、public成员(2)protected成员(3)不可访问(4)接口不变8.1.3 利用继承能够实现 (1) 。这种实现缩短了程序开发的时间,VC+中的 (2) 很好地体现了这一点。答案:(1)代码的复用(2)MFC编程8.1.4 一个派生类只有一个直接基类的情况称为 (1) ,而有多个直接基类的情况称为(2) 。继承体现了类的 (3) 概念,这在MFC中得到了很好表现,MFC中只采用了 (4) 。答案:(1)单继承(2)多重继承(3)层次(4)单继承8.1.5 C+中多态性包括两种多态性: (1) 和 (2) 。前者是通过 (3) 实现的,而后者是通过 (4) 和 (5) 来实现的。答案:(
3、1)编译时的(2)运行时的(3)函数和运算符的重载(4)类继承关系(5)虚函数8.1.6 在基类中将一个成员函数说明成虚函数后,在其派生类中只要 (1) 、 (2) 和 (3) 完全一样就认为是虚函数,而不必再加关键字 (4) 。如有任何不同,则认为是 (5) 而不是虚函数。除了非成员函数不能作为虚函数外, (6) 、 (7) 和 (8) 也不能作为虚函数。答案:(1)同虚函数名(2)同参数表(3)同返回类型。如基类中返回基类指针,而派生类中返回派生类指针是允许的(4)virtual(5)重载(6)静态成员函数(7)内联函数(8)构造函数8.1.7 纯虚函数定义时在函数参数表后加 (1) ,它
4、表明程序员对函数 (2) ,其本质是将指向函数体的指针定为 (3) 。答案:(1)=0(2)不定义(3)NULL8.2 简答题8.2.1 构造函数和析构函数可以继承吗?派生类构造函数各部分的执行次序是怎样的?答:构造函数和析构函数不可以继承。派生类构造函数各部分的执行次序是:1. 调用基类构造函数,按它们在派生类声明的先后顺序,依次调用。2. 调用新增成员对象的构造函数,按它们在类定义中声明的先后顺序,依次调用。3. 派生类的构造函数体中的操作。8.2.2 什么叫派生类的同名覆盖(override)?答:如果派生类声明了一个和某个基类成员同名的新成员(当然如是成员函数,参数表也必须一样,否则是
5、重载),派生类中的新成员就屏蔽了基类同名成员,类似函数中的局部变量屏蔽全局变量。称为同名覆盖(override)。8.2.3 派生类的析构函数中需完成什么任务?是否要编写对基数和成员对象的析构函数的调用?为什么?答:析构函数的功能是作善后工作,析构函数无返回类型也没有参数,情况比较简单。派生类析构函数定义格式与非派生类无任何差异,不要编写对基数和成员对象的析构函数的调用,只要在函数体内把派生类新增一般成员处理好就可以了,因为对新增的成员对象和基类的善后工作,系统会自己调用成员对象和基类的析构函数来完成。8.2.4 为什么要使用虚基类?怎样定义虚基类?用一个实例来解释虚基类在其派生类中的存储方式
6、。答:在多重继承是有可能出现同一基类的两个拷贝,为避免这种情况,可使用虚基类。虚基类(virtual base class)定义方式如下:class 派生类名:virtual 访问限定符 基类类名.;class 派生类名:访问限定符 virtual 基类类名.;virtual 关键字只对紧随其后的基类名起作用。如下派生:存储关系如(b),在职研究生类有两个Person拷贝。采用虚基类后存储关系如下: 采用虚基类后在职研究生类储存图StudentGStudentEGStudentPersonStudent新成员GStudent新成员PersonEmployee新成员Person成员EGStude
7、nt新成员PersonPersonEmployee在职研究生类只有一个Person拷贝。8.2.5 简单叙述派生类与基类的赋值兼容规则。答:凡是基类所能解决的问题,公有派生类都可以解决。在任何需要基类对象的地方都可以用公有派生类的对象来代替,这条规则称赋值兼容规则。它包括以下情况:1 派生类的对象可以赋值给基类的对象,这时是把派生类对象中从对应基类中继承来的成员赋值给基类对象。反过来不行,因为派生类的新成员无值可赋。2 可以将一个派生类的对象的地址赋给其基类的指针变量,但只能通过这个指针访问派生类中由基类继承来的成员,不能访问派生类中的新成员。同样也不能反过来做。3 派生类对象可以初始化基类的
8、引用。引用是别名,但这个别名只能包含派生类对象中的由基类继承来的成员。8.2.6 在类中定义对象成员称为复合或嵌套,请对比复合与继承的异同之处。答:成员对象是嵌套的概念,使用成员对象中的成员,只能直接访问(对象名加点号加成员名)公有成员。在类的成员函数中不能直接访问和处理成员对象的私有和保护成员,而要通过成员对象的接口去间接访问和处理。某些应用中,对象成员可以代替继承中的基类。基类在派生类中只能继承一个(间接基类不在讨论之中)不能同时安排两个,否则成员名即使使用域分辨符也会发生冲突,但如果一定要用两个,只能采用成员对象。所以采用成员对象更加灵活。两者不是对立的,而是互为补充的。8.2.7 比较
9、派生与模板各自的优点。答:模板追求的是运行效率,而派生追求的是编程的效率。通用性是模板库的设计出发点之一,这是由泛型算法和函数对象等手段达到的。为了运行的效率,类模板是相互独立的,即独立设计,没有使用继承的思想。对类模板的扩展是采用适配子(adapter)来完成的。应该说派生类的目标之一也是代码的复用和程序的通用性,最典型的就是MFC,派生类的优点是可以由简到繁,逐步深入,程序编制过程中可以充分利用前面的工作,一步步完成一个复杂的任务。8.2.8 是否使用了虚函数就能实现运行时的多态性?怎样才能实现运行时的多态性?答:不是。实现动态多态性时,必须使用基类类型的指针变量或引用,使该指针指向该基类
10、的不同派生类的对象,并通过该指针指向虚函数,才能实现动态的多态性。8.2.9 为什么析构函数总是要求说明为虚函数?答:在基类中及其派生类中都动态分配内存空间时,必须把析构函数定义为虚函数,实现撤消对象时的多态性。根据赋值兼容规则可以用基类的指针指向派生类对象,如果由该指针撤销派生类对象,则必须将析构函数说明为虚函数,实现多态性,自动调用派生类析构函数。我们总是要求将类设计成通用的,无论其他程序员怎样调用都必须保证不出错,所以必须把析构函数定义为虚函数。8.2.10 什么是抽象类?含有纯虚函数的类是抽象类吗?答:若定义一个类,它只能用作基类来派生出新的类,而不能用来定义对象,则称为抽象类。含有纯
11、虚函数的类是抽象类。8.2.11 能否不提供源代码,做到用户自行把通用的软件转化为专用软件?怎样实现?答:能不提供源代码,做到用户自行把通用的软件转化为专用软件。动态联编不一定要源代码,可以只有头文件和对象文件的.obj文件。软件开发商可在不透露其秘密的情况下发行.obj形式的软件,然后由程序员利用继承机制,从所购得的类中派生出新类。能与软件开发商提供的类一起运行的软件也能与派生类一起运行,并能通过动态联编使用这些派生类中重定义的虚函数。比如通用的财务软件可以转化为某公司的专用软件。二. 编程与综合练习题8.3 请用类的派生方式来组织下列动物实体与概念:动物,脊椎动物亚门,节肢动物门,鱼纲,鸟
12、纲,爬行纲,哺乳纲,昆虫纲,鲨鱼,青鱼,海马,鹦鹉,海鸥,喜鹊,蝙蝠,翼龙,蜻蜓,金龟,扬子鳄,袋鼠,金丝猴,虎,蜈蚣,蜘蛛,蝗虫,知了,螃蟹,虾。解:动物派生出:脊椎动物亚门和节肢动物门。脊椎动物亚门派生出:鱼纲,鸟纲,爬行纲,哺乳纲。鱼纲派生出:鲨鱼,青鱼,海马。鸟纲派生出:鹦鹉,海鸥,喜鹊。爬行纲派生出:翼龙,金龟,扬子鳄。哺乳纲派生出:蝙蝠,袋鼠,金丝猴,虎。节肢动物门派生出:昆虫纲,蜈蚣(多足纲),蜘蛛(蜘形纲),螃蟹,虾(甲壳纲)。昆虫纲派生出:蜻蜓,蝗虫,知了。8.4 定义商品类及其多层的派生类。以商品类为基类。第一层派生出服装类、家电类、车辆类。第二层派生出衬衣类、外衣类、帽子
13、类、鞋子类;空调类、电视类、音响类;自行车类、轿车类、摩托车类。要求给出基本属性和派生过程中增加的属性。解:按题意没有操作,所以只列出数据成员,也不再检验#include using namespace std;class Commoditydouble price; /价格 char name20;/商品名char manufacturer20;/生产厂家int items;/数量;class Clothing:public Commodity/服装类char texture20;/材料质地;class Electric_Appliance:public Commodity/家电类enum
14、Black,Whitetype;/黑白家电;class Vehicle:public Commodity/车辆类int wheel_num;/车轮数量;class Shirt:public Clothing/衬衣类enum Formal,CasualStyle;/式样:正式、休闲;class Garment:public Clothing/外衣类enum Jacket,CoatStyle;/式样:夹克、外套;class Hat:public Clothing/帽子类;enum Winter,Summer,Spring_AutumnStyle;/季节风格;class Shoes:public C
15、lothing/鞋子类enum Winter,Summer,Spring_AutumnStyle;/季节风格;class Air_Cindition:public Electric_Appliance/空调bool warm_cool; /是否冷暖float power;/功率;class Television:public Electric_Appliance/电视类int Size; /尺寸bool isColor;/是否彩色;class Acoustics:public Electric_Appliance/音响类int speaker_num; /喇叭数目float power;/功率
16、;class Bicycle:public Vehicle/自行车类int speed_grades;/调速级数int wheel_size;/轮子大小;class Car:public Vehicle/轿车类float volume;/排气量bool isSkylight;/是否有天窗int box_num;/厢数;class Motorcycle:public Vehicle/摩托车类float volume;/排气量;int main()return 0; 8.5 以点(point)类为基类,重新定义矩形类和圆类。点为直角坐标点,矩形水平放置,由左下方的顶点和长宽定义。圆由圆心和半径定义
17、。派生类操作判断任一坐标点是在图形内,还是在图形的边缘上,还是在图形外。缺省初始化图形退化为点。要求包括拷贝构造函数。编程测试类设计是否正确。解:#include #include using namespace std;const double PI=3.;class Pointprivate:double x,y;public:Point()x = 0; y = 0; Point(double xv,double yv)x = xv;y = yv;Point(Point& pt) x = pt.x; y = pt.y; double getx()return x;double gety()
18、return y;double Area()return 0;void Show()coutx=x y=yendl;class Circle :public Pointdouble radius;public:Circle()radius = 0;Circle(double xv,double yv,double vv):Point(xv,yv)radius = vv;Circle(Circle& cc):Point(cc)radius = cc.radius; /拷贝构造函数double Area()return PI*radius*radius;void Show()/注意怎样访问基类的数
19、据成员coutx=getx()ty=gety()tradius=radiusendl; int position(Point &pt)double distance = sqrt(getx()-pt.getx()*(getx()-pt.getx() +(gety()-pt.gety()*(gety()-pt.gety(); double s=distance-radius;if(s=0) return 0; /在圆上else if(s0) return -1;/在圆内else return 1;/在圆外;class Rectangle:public Pointdouble width,leng
20、th;public:Rectangle()width=0; length=0; Rectangle(double xv,double yv,double wv,double lv):Point(xv,xv)width = wv;length= lv;Rectangle(Rectangle& rr):Point(rr)width = rr.width;length = rr.length;double Area()return width*length;void Show()coutx=getx()ty=gety()t;coutwidth=widthtlength=lengthendl;int
21、position(Point &pt);int Rectangle:position(Point &pt)double s1,s2;s1 = (pt.getx()-getx(); s2=(pt.gety()-gety();if(s1=0|s1=width)&s2=length)|(s2=0|s2=length)&s1=width) return 0; else if(s1width&s2length) return -1;/0在矩形上,-1在矩形内else return 1;/1在矩形外int main()Circle cc1(3,4,5),cc2,cc3(cc1);Rectangle rt1
22、(0,0,6,8),rt2,rt3(rt1);Point p1(0,0),p2(6,8),p3(3,3),p4(8,4),p5(8,8);cc1.Show();cc2.Show();rt1.Show();rt2.Show();cout点p1:;p1.Show();cout矩形rt3:t;rt3.Show();switch(rt3.position(p1)case 0:cout在矩形上endl;break;case -1:cout在矩形内endl;break;case 1:cout在矩形外endl;break;cout圆cc3:t;cc3.Show();switch(cc3.position(p
23、1)case 0:cout在圆上endl;break;case -1:cout在圆内endl;break;case 1:cout在圆外endl;break;cout点p2:;p2.Show();cout矩形rt3:t;rt3.Show();switch(rt3.position(p2)case 0:cout在矩形上endl;break;case -1:cout在矩形内endl;break;case 1:cout在矩形外endl;break;cout圆cc3:t;cc3.Show();switch(cc3.position(p2)case 0:cout在圆上endl;break;case -1:
24、cout在圆内endl;break;case 1:cout在圆外endl;break;cout点p3:;p3.Show();cout矩形rt3:t;rt3.Show();switch(rt3.position(p3)case 0:cout在矩形上endl;break;case -1:cout在矩形内endl;break;case 1:cout在矩形外endl;break;cout圆cc3:t;cc3.Show();switch(cc3.position(p3)case 0:cout在圆上endl;break;case -1:cout在圆内endl;break;case 1:cout在圆外end
25、l;break;cout点p4:;p4.Show();cout矩形rt3:t;rt3.Show();switch(rt3.position(p4)case 0:cout在矩形上endl;break;case -1:cout在矩形内endl;break;case 1:cout在矩形外endl;break;cout圆cc3:t;cc3.Show();switch(cc3.position(p4)case 0:cout在圆上endl;break;case -1:cout在圆内endl;break;case 1:cout在圆外endl;break;cout点p5:;p5.Show();cout矩形rt
26、3:t;rt3.Show();switch(rt3.position(p5)case 0:cout在矩形上endl;break;case -1:cout在矩形内endl;break;case 1:cout在矩形外endl;break;cout圆cc3:t;cc3.Show();switch(cc3.position(p5)case 0:cout在圆上endl;break;case -1:cout在圆内endl;break;case 1:cout在圆外endl;break;return 0;8.6 几何形体的派生关系如下:对平面形体有长和面积,对立体有表面积和体积,对几何图形基类,周长、面积和体
27、积应怎样计算(用什么函数)?对平面图形体积怎样计算(用什么函数)?对立体图形周长怎么计算(用什么函数)?要求实现运行时的多态性。请编程,并测试。解:运行时的多态性要用指针#include #include using namespace std;const double PI=3.;class Geometric_shape/几何图形public:virtual double perimeter()=0;/周长virtual double area()=0;/面积virtual double volume()=0;/体积virtual void Show();class Circle :pub
28、lic Geometric_shape/圆double radius;public:Circle()radius = 0; Circle(double vv)radius = vv;double perimeter()return 2.0*PI*radius;/周长double area()return PI*radius*radius;/面积double volume()return 0;/体积void Show()coutradius=radiusendl;class Rectangle:public Geometric_shape/矩形double width,length;public
29、:Rectangle()width=0; length=0;/长宽Rectangle(double wid,double len)width = wid;length= len;Rectangle(Rectangle& rr)width = rr.width;length = rr.length;double perimeter()return 2.0*(width+length);/周长double area()return width*length;/面积double volume()return 0;/体积void Show()coutwidth=widthtlength=lengthe
30、ndl;class Triangle:public Geometric_shape/三角形double a,b,c;public:Triangle()a=0;b=0;c=0;Triangle(double v1,double v2,double v3)a = v1;b = v2;c = v3;double perimeter()return a+b+c;/周长double area()double s=(a+b+c)/2.0;return sqrt(s*(s-a)*(s-b)*(s-c);/面积double volume()return 0;/体积void Show()couta=atb=bt
31、c=cendl;class Box:public Rectangle/长方体double height;public:Box()height=0;Box(double wid,double len,double heg):Rectangle(wid,len)height=heg;double volume()return area()*height;/体积;class Cylinder:public Circle /圆柱体double height;public:Cylinder()height=0;Cylinder(double vv,double heg):Circle(vv)height
32、=heg;double volume()return area()*height;/体积;class Cone: public Circle /圆锥double height;public:Cone()height=0;Cone(double vv,double heg):Circle(vv)height=heg;double volume()return area()*height/3;/体积;class T_pyramid:public Triangle/三棱锥double height;public:T_pyramid()height=0;T_pyramid(double v1,doub
33、le v2,double v3,double heg):Triangle(v1,v2,v3)height=heg;double volume()return area()*height/3;/体积;class T_prism:public Triangle/三棱柱double height;public:T_prism()height=0;T_prism(double v1,double v2,double v3,double heg):Triangle(v1,v2,v3)height=heg;double volume()return area()*height;/体积;int main()
34、Geometric_shape * gs;Circle cc1(10);Rectangle rt1(6,8);Triangle tg1(3,4,5);Box bx1(6,8,3);Cylinder cl1(10,3);Cone cn1(10,3);T_pyramid tpy1(3,4,5,3);T_prism tpr1(3,4,5,3);cc1.Show();/静态cout圆周长:cc1.perimeter()t;cout圆面积:cc1.area()t;cout圆体积:cc1.volume()Show();cout矩形周长:perimeter()t;cout矩形面积:area()t;cout矩
35、形体积:volume()Show();cout三角形周长:perimeter()t;cout三角形面积:area()t;cout三角形体积:volume()Show();cout长方体底周长:perimeter()t;cout长方体底面积:area()t;cout长方体体积:volume()Show();cout圆柱体底周长:perimeter()t;cout圆柱体底面积:area()t;cout圆柱体体积:volume()Show();cout圆锥体底周长:perimeter()t;cout圆锥体底面积:area()t;cout圆锥体体积:volume()Show();cout三棱锥底周长:
36、perimeter()t;cout三棱锥底面积:area()t;cout三棱锥体积:volume()Show();cout三棱柱底周长:perimeter()t;cout三棱柱底面积:area()t;cout三棱柱体积:volume()endl;return 0;8.7 某公司雇员(employee)包括经理(manager),技术人员(technician)和销售员(salesman)。开发部经理(developermanger),既是经理也是技术人员。销售部经理(salesmanager),既是经理也是销售员。以employ类为虚基类派生出manager,technician和salesm
37、an类;再进一步派生出developermanager和salesmanager类。employee类的属性包括姓名、职工号、工资级别,月薪(实发基本工资加业绩工资)。操作包括月薪计算函数(pay()),该函数要求输入请假天数,扣去应扣工资后,得出实发基本工资。technician类派生的属性有每小时附加酬金和当月工作时数,及研究完成进度系数。业绩工资为三者之积。也包括同名的pay()函数,工资总额为基本工资加业绩工资。salesman类派生的属性有当月销售额和酬金提取百分比,业绩工资为两者之积。也包括同名的pay()函数,工资总额为基本工资加业绩工资。manager类派生属性有固定奖金额和业
38、绩系数,业绩工资为两者之积。工资总额也为基本工资加业绩工资。而developermanager类,pay()函数是将作为经理和作为技术人员业绩工资之和的一半作为业绩工资。salesamanager类,pay()函数则是经理的固定奖金额的一半,加上部门总销售额与提成比例之积,这是业绩工资。编程实现工资管理。特别注意pay()的定义和调用方法:先用同名覆盖,再用运行时多态。8.8 为上题添加拷贝构造函数,并测试是否正确。解:#include#include using namespace std;static int Grades=500,600,750,1000,1400,2000,2800,4
39、000;class employeeprotected:string name;/姓名int ID;/职工号int grade;/工资级别double salary;/月double base_salary;/基本月薪double career_salary;/业绩工资public:employee(string=,int=0,int=0); employee(employee &); /拷贝构造函数virtual void pay(); /月薪计算函数void show();double getsalary()return salary;double getbase_salary()return base_salary;double getcareer_salary()return career_salary;employee:employee(string nn,int id,int gr)name=nn;ID = id;grade = gr; salary=0; /月薪base_salary=0; /基本月薪career_salary=0; /业绩工资employee:employee(employee &emp) /拷贝构造函数name=emp.name;ID=emp.ID;grade =emp.grade; salary=emp.salary;
限制150内