搜索
您的当前位置:首页继承与多态习题

继承与多态习题

时间:2024-03-10 来源:乌哈旅游
 继承与多态习题

一. 基本概念与基础知识自测题

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)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) 来实现的。 答案:(1)编译时的

(2)运行时的

(3)函数和运算符的重载 (4)类继承关系 (5)虚函数

8.1.6 在基类中将一个成员函数说明成虚函数后,在其派生类中只要 (1) 、 (2) 和

2

(3) 完全一样就认为是虚函数,而不必再加关键字 (4) 。如有任何不同,则认为是 (5) 而不是虚函数。除了非成员函数不能作为虚函数外, (6) 、 (7) 和 (8) 也不能作为虚函数。 答案:(1)同虚函数名

(2)同参数表

(3)同返回类型。如基类中返回基类指针,而派生类中返回派生类指针是允许的 (4)virtual (5)重载

(6)静态成员函数 (7)内联函数 (8)构造函数

8.1.7 纯虚函数定义时在函数参数表后加 (1) ,它表明程序员对函数 (2) ,其本质

是将指向函数体的指针定为 (3) 。 答案:(1)=0

(2)不定义 (3)NULL

8.2 简答题

8.2.1 构造函数和析构函数可以继承吗?派生类构造函数各部分的执行次序是怎样的? 答:构造函数和析构函数不可以继承。派生类构造函数各部分的执行次序是: 1. 调用基类构造函数,按它们在派生类声明的先后顺序,依次调用。

2. 调用新增成员对象的构造函数,按它们在类定义中声明的先后顺序,依次调用。 3. 派生类的构造函数体中的操作。

8.2.2 什么叫派生类的同名覆盖(override)?

答:如果派生类声明了一个和某个基类成员同名的新成员(当然如是成员函数,参数表也必须一样,否则是重载),派生类中的新成员就屏蔽了基类同名成员,类似函数中的局部变量屏蔽全局变量。称为同名覆盖(override)。

8.2.3 派生类的析构函数中需完成什么任务?是否要编写对基数和成员对象的析构函数的

调用?为什么?

答:析构函数的功能是作善后工作,析构函数无返回类型也没有参数,情况比较简单。派生类析构函数定义格式与非派生类无任何差异,不要编写对基数和成员对象的析构函数的调用,只要在函数体内把派生类新增一般成员处理好就可以了,因为对新增的成员对象和基类的善后工作,系统会自己调用成员对象和基类的析构函数来完成。

8.2.4 为什么要使用虚基类?怎样定义虚基类?用一个实例来解释虚基类在其派生类中的

存储方式。

答:在多重继承是有可能出现同一基类的两个拷贝,为避免这种情况,可使用虚基类。虚基类(virtual base class)定义方式如下:

class 派生类名:virtual 访问限定符 基类类名{...}; class 派生类名:访问限定符 virtual 基类类名{...}; virtual 关键字只对紧随其后的基类名起作用。

继承与派生习题 3

如下派生:

class Personint No身份证号……class Personint No身份证号……class Studentint No学生号……class Employeeint No工作证号……class GStudentint No研究生号……Person成员Student新成员GStudent新成员class EGStudentint No在职学号……(a)派生关系Person成员Employee新成员EGStudent新成员(b)存储图PersonEmployeeEGStudentPersonStudentGStudent

存储关系如(b),在职研究生类有两个Person拷贝。采用虚基类后存储关系如下: Person Person Student Student新成员 GStudent GStudent新成员 EGStudent Person Person Employe Employee新成员

Person成员

EGStudent新成员 采用虚基类后在职研究生类储存图

在职研究生类只有一个Person拷贝。

8.2.5 简单叙述派生类与基类的赋值兼容规则。

答:凡是基类所能解决的问题,公有派生类都可以解决。在任何需要基类对象的地方都可以

4

用公有派生类的对象来代替,这条规则称赋值兼容规则。它包括以下情况:

1. 派生类的对象可以赋值给基类的对象,这时是把派生类对象中从对应基类中继承来的成

员赋值给基类对象。反过来不行,因为派生类的新成员无值可赋。

2. 可以将一个派生类的对象的地址赋给其基类的指针变量,但只能通过这个指针访问派生

类中由基类继承来的成员,不能访问派生类中的新成员。同样也不能反过来做。

3. 派生类对象可以初始化基类的引用。引用是别名,但这个别名只能包含派生类对象中的

由基类继承来的成员。

8.2.6 在类中定义对象成员称为复合或嵌套,请对比复合与继承的异同之处。

答:成员对象是嵌套的概念,使用成员对象中的成员,只能直接访问(对象名加点号加成员名)公有成员。在类的成员函数中不能直接访问和处理成员对象的私有和保护成员,而要通过成员对象的接口去间接访问和处理。某些应用中,对象成员可以代替继承中的基类。 基类在派生类中只能继承一个(间接基类不在讨论之中)不能同时安排两个,否则成员名即使使用域分辨符也会发生冲突,但如果一定要用两个,只能采用成员对象。所以采用成员对象更加灵活。两者不是对立的,而是互为补充的。

8.2.7 比较派生与模板各自的优点。

答:模板追求的是运行效率,而派生追求的是编程的效率。 通用性是模板库的设计出发点之一,这是由泛型算法和函数对象等手段达到的。为了运行的效率,类模板是相互独立的,即独立设计,没有使用继承的思想。对类模板的扩展是采用适配子(adapter)来完成的。应该说派生类的目标之一也是代码的复用和程序的通用性,最典型的就是MFC,派生类的优点是可以由简到繁,逐步深入,程序编制过程中可以充分利用前面的工作,一步步完成一个复杂的任务。

8.2.8 是否使用了虚函数就能实现运行时的多态性?怎样才能实现运行时的多态性? 答:不是。实现动态多态性时,必须使用基类类型的指针变量或引用,使该指针指向该基类的不同派生类的对象,并通过该指针指向虚函数,才能实现动态的多态性。

8.2.9 为什么析构函数总是要求说明为虚函数?

答:在基类中及其派生类中都动态分配内存空间时,必须把析构函数定义为虚函数,实现撤消对象时的多态性。根据赋值兼容规则可以用基类的指针指向派生类对象,如果由该指针撤销派生类对象,则必须将析构函数说明为虚函数,实现多态性,自动调用派生类析构函数。我们总是要求将类设计成通用的,无论其他程序员怎样调用都必须保证不出错,所以必须把析构函数定义为虚函数。

8.2.10 什么是抽象类?含有纯虚函数的类是抽象类吗? 答:若定义一个类,它只能用作基类来派生出新的类,而不能用来定义对象,则称为抽象类。含有纯虚函数的类是抽象类。

8.2.11 能否不提供源代码,做到用户自行把通用的软件转化为专用软件?怎样实现? 答:能不提供源代码,做到用户自行把通用的软件转化为专用软件。动态联编不一定要源代码,可以只有头文件和对象文件的.obj文件。软件开发商可在不透露其秘密的情况下发行.obj形式的软件,然后由程序员利用继承机制,从所购得的类中派生出新类。能与软件开发商提供的类一起运行的软件也能与派生类一起运行,并能通过动态联编使用这些派生类中重定义

继承与派生习题 5

的虚函数。比如通用的财务软件可以转化为某公司的专用软件。

二. 编程与综合练习题

8.3 请用类的派生方式来组织下列动物实体与概念:动物,脊椎动物亚门,节肢动物门,

鱼纲,鸟纲,爬行纲,哺乳纲,昆虫纲,鲨鱼,青鱼,海马,鹦鹉,海鸥,喜鹊,蝙蝠,翼龙,蜻蜓,金龟,扬子鳄,袋鼠,金丝猴,虎,蜈蚣,蜘蛛,蝗虫,知了,螃蟹,虾。

解:动物派生出:脊椎动物亚门和节肢动物门。

脊椎动物亚门派生出:鱼纲,鸟纲,爬行纲,哺乳纲。 鱼纲派生出:鲨鱼,青鱼,海马。 鸟纲派生出:鹦鹉,海鸥,喜鹊。 爬行纲派生出:翼龙,金龟,扬子鳄。 哺乳纲派生出:蝙蝠,袋鼠,金丝猴,虎。 节肢动物门派生出:昆虫纲,蜈蚣(多足纲),蜘蛛(蜘形纲),螃蟹,虾(甲壳纲)。 昆虫纲派生出:蜻蜓,蝗虫,知了。

8.4 定义商品类及其多层的派生类。以商品类为基类。第一层派生出服装类、家电类、车

辆类。第二层派生出衬衣类、外衣类、帽子类、鞋子类;空调类、电视类、音响类;自行车类、轿车类、摩托车类。要求给出基本属性和派生过程中增加的属性。 解:按题意没有操作,所以只列出数据成员,也不再检验 #include using namespace std; class Commodity{ double price; //价格 char name[20];//商品名 char manufacturer[20];//生产厂家 int items;//数量 };

class Clothing:public Commodity{//服装类 char texture[20];//材料质地 };

class Electric_Appliance:public Commodity{//家电类 enum {Black,White}type;//黑白家电 };

class Vehicle:public Commodity{//车辆类 int wheel_num;//车轮数量 };

class Shirt:public Clothing{//衬衣类 enum {Formal,Casual}Style;//式样:正式、休闲 };

class Garment:public Clothing{//外衣类 enum {Jacket,Coat}Style;//式样:夹克、外套 };

class Hat:public Clothing{//帽子类;

6

enum {Winter,Summer,Spring_Autumn}Style;//季节风格 };

class Shoes:public Clothing{//鞋子类 enum {Winter,Summer,Spring_Autumn}Style;//季节风格 };

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; //功率 };

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)类为基类,重新定义矩形类和圆类。点为直角坐标点,矩形水平放置,

由左下方的顶点和长宽定义。圆由圆心和半径定义。派生类操作判断任一坐标点是在图形内,还是在图形的边缘上,还是在图形外。缺省初始化图形退化为点。要求包括拷贝构造函数。编程测试类设计是否正确。 解:

#include #include using namespace std; const double PI=3.; class Point{ private:

继承与派生习题 7

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(){return y;} double Area(){return 0;} void Show(){cout<<\"x=\"<class Circle :public Point{ double 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(){//注意怎样访问基类的数据成员 cout<<\"x=\"<class Rectangle:public Point{ double width,length; 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(){ cout<<\"x=\"<8

cout<<\"width=\"<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(s1int main(){ Circle cc1(3,4,5),cc2,cc3(cc1); Rectangle rt1(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:\"<<'\'; rt3.Show(); switch(rt3.position(p1)){ case 0:cout<<\"在矩形上\"<在矩形上,-1在矩形内 //1在矩形外 //0 继承与派生习题 9

cout<<\"圆cc3:\"<<'\'; cc3.Show();

switch(cc3.position(p2)){

case 0:cout<<\"在圆上\"<cout<<\"点p3:\"; p3.Show();

cout<<\"矩形rt3:\"<<'\'; rt3.Show();

switch(rt3.position(p3)){

case 0:cout<<\"在矩形上\"<cout<<\"圆cc3:\"<<'\'; cc3.Show();

switch(cc3.position(p3)){

case 0:cout<<\"在圆上\"<cout<<\"点p4:\"; p4.Show();

cout<<\"矩形rt3:\"<<'\'; rt3.Show();

switch(rt3.position(p4)){

case 0:cout<<\"在矩形上\"<cout<<\"圆cc3:\"<<'\'; cc3.Show();

switch(cc3.position(p4)){

case 0:cout<<\"在圆上\"<cout<<\"点p5:\"; p5.Show();

cout<<\"矩形rt3:\"<<'\'; rt3.Show();

switch(rt3.position(p5)){

10

} 8.6

case 0:cout<<\"在矩形上\"<cout<<\"圆cc3:\"<<'\'; cc3.Show();

switch(cc3.position(p5)){

case 0:cout<<\"在圆上\"<return 0;

几何形体的派生关系如下:

几何图形 geometric_shape)矩形 rectangle 圆 circle 三角形(triangle)长方体 box)圆柱 cylinder)圆锥 cone)三棱锥(t_pyramid)三棱柱(t_prism)

对平面形体有长和面积,对立体有表面积和体积,对几何图形基类,周长、面积和体积应怎样计算(用什么函数)?对平面图形体积怎样计算(用什么函数)?对立体图形周长怎么计算(用什么函数)?要求实现运行时的多态性。请编程,并测试。 解:运行时的多态性要用指针 #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 :public Geometric_shape{//圆 double radius; public: Circle(){radius = 0; }

继承与派生习题 11

Circle(double vv){radius = vv;} double perimeter(){return 2.0*PI*radius;} //周长 double area(){return PI*radius*radius;} //面积 double volume(){return 0;} //体积 void Show(){cout<<\"radius=\"<class Rectangle:public Geometric_shape{//矩形 double width,length; public: 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(){cout<<\"width=\"<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(){cout<<\"a=\"<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;} //体积 };

12

class Cylinder:public Circle {//圆柱体 double height; public: Cylinder(){height=0;} Cylinder(double vv,double heg):Circle(vv){height=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,double 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(){ 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<<\"圆周长:\"<继承与派生习题 13

} 8.7

gs->Show();

cout<<\"矩形周长:\"<perimeter()<<'\'; cout<<\"矩形面积:\"<area()<<'\';

cout<<\"矩形体积:\"<volume()<Show();

cout<<\"三角形周长:\"<perimeter()<<'\'; cout<<\"三角形面积:\"<area()<<'\';

cout<<\"三角形体积:\"<volume()<Show();

cout<<\"长方体底周长:\"<perimeter()<<'\'; cout<<\"长方体底面积:\"<area()<<'\'; cout<<\"长方体体积:\"<volume()<Show();

cout<<\"圆柱体底周长:\"<perimeter()<<'\'; cout<<\"圆柱体底面积:\"<area()<<'\'; cout<<\"圆柱体体积:\"<volume()<Show();

cout<<\"圆锥体底周长:\"<perimeter()<<'\'; cout<<\"圆锥体底面积:\"<area()<<'\'; cout<<\"圆锥体体积:\"<volume()<Show();

cout<<\"三棱锥底周长:\"<perimeter()<<'\'; cout<<\"三棱锥底面积:\"<area()<<'\'; cout<<\"三棱锥体积:\"<volume()<Show();

cout<<\"三棱柱底周长:\"<perimeter()<<'\'; cout<<\"三棱柱底面积:\"<area()<<'\'; cout<<\"三棱柱体积:\"<volume()<某公司雇员(employee)包括经理(manager),技术人员(technician)和销售员(salesman)。开发部经理(developermanger),既是经理也是技术人员。销售部经理(salesmanager),既是经理也是销售员。

以employ类为虚基类派生出manager,technician和salesman类;再进一步派生出developermanager和salesmanager类。

employee类的属性包括姓名、职工号、工资级别,月薪(实发基本工资加业绩工资)。操作包括月薪计算函数(pay()),该函数要求输入请假天数,扣去应扣工资后,

14

得出实发基本工资。

technician类派生的属性有每小时附加酬金和当月工作时数,及研究完成进度系数。业绩工资为三者之积。也包括同名的pay()函数,工资总额为基本工资加业绩工资。

salesman类派生的属性有当月销售额和酬金提取百分比,业绩工资为两者之积。也包括同名的pay()函数,工资总额为基本工资加业绩工资。

manager类派生属性有固定奖金额和业绩系数,业绩工资为两者之积。工资总额也为基本工资加业绩工资。

而developermanager类,pay()函数是将作为经理和作为技术人员业绩工资之和的一半作为业绩工资。

salesamanager类,pay()函数则是经理的固定奖金额的一半,加上部门总销售额与提成比例之积,这是业绩工资。

编程实现工资管理。特别注意pay()的定义和调用方法:先用同名覆盖,再用运行时多态。 解:

#include #include using namespace std;

static int Grades[]={500,600,750,1000,1400,2000,2800,4000}; class employee{ protected: string name;//姓名 int ID;//职工号 int grade;//工资级别 double salary;//月 double base_salary;//基本月薪 double career_salary;//业绩工资 public: employee(string=\"\int=0,int=0); 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;//业绩工资 }

void employee::show(){ cout<继承与派生习题 15

}

void employee::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; base_salary = Grades[grade]*(23 - days)/23; career_salary = base_salary/2;//普通员工业绩工资为基本工资的一半 salary = base_salary+career_salary; }

class manager:virtual public employee{//虚基类 protected: double prize;//固定奖金额 double factor;//业绩系数 public: manager(string=\"\int=0,int=0,double=0); void pay(); };

manager::manager(string nn,int id,int gr,double pr):employee(nn,id,gr){ prize = pr;//固定奖金额 factor = 0; }

void manager::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入业绩系数:\\n\"; cin>>factor; base_salary = Grades[grade]*(23 - days)/23; career_salary = prize*factor*(23 - days)/23; salary = base_salary + career_salary ; }

class technician:virtual public employee{ protected: double hours;//月工作时数 double perhour;//每小时附加酬金 double shfactor;//研究进度系数 public: technician(string=\"\int=0,int=0,double=0); void pay(); };

technician::technician(string nn,int id,int gr,double phr):employee(nn,id,gr){ hours = 0; perhour = phr;//每小时附加酬金 shfactor = 0;

16

}

void technician::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入研究进度系数:\\n\"; cin>>shfactor; hours=8*(23-days); base_salary = Grades[grade]*(23 - days)/23; career_salary = perhour*hours*shfactor*(23 - days)/23; salary= base_salary + career_salary ; }

class salesman:virtual public employee{ protected: double amount;//销售额 double slfactor;//提成比例 public: salesman(string=\"\int=0,int=0,double=0); void pay(); };

salesman::salesman(string nn,int id,int gr,double slfac):employee(nn,id,gr) { amount = 0; slfactor = slfac;//提成比例 }

void salesman::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入销售额:\\n\"; cin>>amount; base_salary = Grades[grade]*(23 - days)/23; career_salary = amount*slfactor; salary = base_salary + career_salary ; }

class developermanager:public manager,public technician { public: developermanager(string=\"\int id=0,int gr=0,double pr=0, double phr=0); void pay(); };

developermanager::developermanager(string nn,int id,int gr,double pr,double phr) :manager(nn,id,gr,pr),technician(nn,id,gr,phr),employee(nn,id,gr){} void developermanager::pay(){ int days;

继承与派生习题 17

cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入业绩系数:\\n\"; cin>>factor; cout<<\"请输入研究进度系数:\\n\"; cin>>shfactor; hours=8*(23-days); base_salary = Grades[grade]*(23 - days)/23;//基本工资 career_salary = perhour*hours*shfactor*(23 - days)/23;//技术人员奖金 career_salary += prize*factor*(23 - days)/23;//加经理业绩工资 career_salary /=2; salary = base_salary + career_salary ; }

class salesmanager:public manager,public salesman{ public: salesmanager(string=NULL,int=0,int=0,double pr=0, double slfac=0); void pay(); };

salesmanager::salesmanager(string nn,int id,int gr,double pr,double slfac) :manager(nn,id,gr,pr),salesman(nn,id,gr,slfac),employee(nn,id,gr){} void salesmanager::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入业绩系数:\\n\"; cin>>factor; cout<<\"请输入销售额:\\n\"; cin>>amount; base_salary = Grades[grade]*(23 - days)/23;//基本工资 career_salary = prize*factor*(23 - days)/23;//经理业绩工资 career_salary /=2; career_salary += amount*slfactor;//加销售业绩工资 salary = base_salary + career_salary ; }

int main(){ employee eml1(\"张伟\ manager mag1(\"姚婕\ technician tec1(\"王茜\ salesman sal1(\"朱明\ developermanager dem1(\"沈俊\ salesmanager sam1(\"况钟\ eml1.pay(); eml1.show(); mag1.pay();

18

mag1.show(); tec1.pay(); tec1.show(); sal1.pay(); sal1.show(); emlp=&dem1; emlp->pay(); emlp->show(); emlp=&sam1; emlp->pay(); emlp->show(); return 0; }

8.8 为上题添加拷贝构造函数,并测试是否正确。 解:

#include #include using namespace std;

static int Grades[]={500,600,750,1000,1400,2000,2800,4000}; class employee{ protected: 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; //业绩工资

继承与派生习题 19

}

employee::employee(employee &emp){ //拷贝构造函数 name=emp.name; ID=emp.ID; grade =emp.grade; salary=emp.salary; //月薪 base_salary=emp.base_salary; //基本月薪 career_salary=emp.career_salary;//业绩工资 }

void employee::show(){ cout<void employee::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; base_salary = Grades[grade]*(23 - days)/23; career_salary = base_salary/2; //普通员工业绩工资为基本工资的一半 salary = base_salary+career_salary; }

class manager:virtual public employee{//虚基类 protected: double prize;//固定奖金额 double factor;//业绩系数 public: manager(string=\"\int=0,int=0,double=0); manager(manager&mag); //拷贝构造函数 void pay(); };

manager::manager(manager&mag):employee(mag){//按赋值兼容规则mag可为employee的实参 prize=mag.prize; factor=mag.factor; }

manager::manager(string nn,int id,int gr,double pr):employee(nn,id,gr){ prize = pr;//固定奖金额 factor = 0; }

void manager::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入业绩系数:\\n\"; cin>>factor; base_salary = Grades[grade]*(23 - days)/23;

20

career_salary = prize*factor*(23 - days)/23; salary = base_salary + career_salary ; }

class technician:virtual public employee{ protected: double hours;//月工作时数 double perhour;//每小时附加酬金 double shfactor;//研究进度系数 public: technician(string=\"\int=0,int=0,double=0); technician(technician &); //拷贝构造函数 void pay(); };

technician::technician(technician& tech):employee(tech){ //拷贝构造函数 hours=tech.hours;//月工作时数 perhour=tech.perhour;//每小时附加酬金 shfactor=tech.shfactor;//研究进度系数 }

technician::technician(string nn,int id,int gr,double phr):employee(nn,id,gr){ hours = 0; perhour = phr;//每小时附加酬金 shfactor = 0; }

void technician::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入研究进度系数:\\n\"; hours=8*(23 - days); cin>>shfactor; base_salary = Grades[grade]*(23 - days)/23; career_salary = perhour*hours*shfactor*(23 - days)/23; salary= base_salary + career_salary ; }

class salesman:virtual public employee{ protected: double amount;//销售额 double slfactor;//提成比例 public: salesman(string=\"\int=0,int=0,double=0); salesman(salesman &); //拷贝构造函数 void pay(); };

salesman::salesman(string nn,int id,int gr,double slfac):employee(nn,id,gr){

继承与派生习题 21

amount = 0; slfactor = slfac;//提成比例 }

salesman::salesman(salesman &sale):employee(sale){ //拷贝构造函数 amount=sale.amount;//销售额 slfactor=sale.slfactor;//提成比例 }

void salesman::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入销售额:\\n\"; cin>>amount; base_salary = Grades[grade]*(23 - days)/23; career_salary = amount*slfactor; salary = base_salary + career_salary ; }

class developermanager:public manager,public technician { public: developermanager(string=\"\int id=0,int gr=0,double pr=0, double phr=0); developermanager(developermanager &); //拷贝构造函数 void pay(); };

developermanager::developermanager(string nn,int id,int gr,double pr,double phr) :manager(nn,id,gr,pr),technician(nn,id,gr,phr),employee(nn,id,gr){} developermanager::developermanager(developermanager &deman) :manager(deman),technician(deman),employee(deman){} //拷贝构造函数 void developermanager::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入业绩系数:\\n\"; cin>>factor; cout<<\"请输入研究进度系数:\\n\"; cin>>shfactor; hours=8*(23 - days); base_salary = Grades[grade]*(23 - days)/23;//基本工资 career_salary = perhour*hours*shfactor*(23 - days)/23;//技术人员奖金 career_salary += prize*factor*(23 - days)/23;//加经理业绩工资 career_salary /=2; salary = base_salary + career_salary ; }

class salesmanager:public manager,public salesman{ public:

22

salesmanager(string=\"\int=0,int=0,double pr=0, double slfac=0); salesmanager(salesmanager &); //拷贝构造函数 void pay(); };

salesmanager::salesmanager(string nn,int id,int gr,double pr,double slfac) :manager(nn,id,gr,pr),salesman(nn,id,gr,slfac),employee(nn,id,gr){} salesmanager::salesmanager(salesmanager& salman) :manager(salman),salesman(salman),employee(salman){} //拷贝构造函数 void salesmanager::pay(){ int days; cout<<\"请输入请假天数:\\n\"; cin>>days; cout<<\"请输入业绩系数:\\n\"; cin>>factor; cout<<\"请输入销售额:\\n\"; cin>>amount; base_salary = Grades[grade]*(23 - days)/23;//基本工资 career_salary = prize*factor*(23 - days)/23;//经理业绩工资 career_salary /=2; career_salary += amount*slfactor;//加销售业绩工资 salary = base_salary + career_salary ; }

int main(){ employee eml1(\"张伟\ manager mag1(\"姚婕\ technician tec1(\"王茜\ salesman sal1(\"朱明\ developermanager dem1(\"沈俊\ salesmanager sam1(\"况钟\ eml1.pay(); eml1.show(); mag1.pay(); mag1.show(); tec1.pay(); tec1.show(); sal1.pay(); sal1.show(); emlp=&dem1; emlp->pay(); emlp->show(); emlp=&sam1; emlp->pay(); emlp->show(); cout<继承与派生习题 23

}

employee eml0(eml1); manager mag0(mag1); technician tec0(tec1); salesman sal0(sal1);

developermanager dem0(dem1); salesmanager sam0(sam1);

cout<<\"输出拷贝结果:\"<show(); emlp=&sam0; emlp->show(); return 0;

8.9 采用纯虚函数实现多态性来建立通用的双向链表派生类。参考【例8.10】和【例7.7】。 解: //ep8_9.h

#include using namespace std;

//首先看结点组织,采用结点类加数据类 class Object{//数据类为抽象类 public: Object(){} virtual bool operator>(Object &)=0;//纯虚函数,参数必须为引用或指针 virtual bool operator!=(Object &)=0;//纯虚函数,参数必须为引用或指针 virtual void Print()=0;//纯虚函数 virtual ~Object(){} //析构函数可为虚函数,构造函数不行 };

class DblNode{ Object* info; //数据域用指针指向数据类对象 DblNode *llink,*rlink; //前驱(左链)、后继(右链)指针 public: DblNode(); //生成头结点的构造函数 ~DblNode(); void Linkinfo(Object* obj); friend class DblList; //以DblList为友元类,DblList可直接访问DblNode的私有函数,与结构一样方便,但更安全 };

DblNode::DblNode(){info=NULL;llink=rlink=NULL;}

24

DblNode::~DblNode(){ cout<<\"删除结点类\"<<'\'; delete info; //释放数据域 }

void DblNode::Linkinfo(Object * obj){info=obj;} //再定义双链表类,选择常用操作 class DblList{ DblNode *head,*current; public: DblList();//构造函数,生成头结点(空链表) ~DblList();//析构函数 void MakeEmpty();//清空链表,只余表头结点 void InsertFront(DblNode* p); //可用来向前生成链表,在表头插入一个结点 void InsertRear(DblNode* p); //可用来向后生成链表,在表尾添加一个结点 void InsertOrder(DblNode* p); //按升序生成链表 DblNode* CreatNode();//创建一个结点(孤立结点) DblNode* DeleteNode(DblNode* p); //删除指定结点 void PrintList();//打印链表的数据域 int Length();//计算链表长度 DblNode *Find(Object & obj);//搜索数据域与定值相同的结点,返回该结点的地址 //其它操作 };

DblList::DblList(){//建立表头结点 head=new DblNode(); head->rlink=head->llink=head; current=NULL; }

DblList::~DblList(){ MakeEmpty();//清空链表 cout<<\"删除头结点:\"; delete head; }

void DblList::MakeEmpty(){ DblNode *tempP; while(head->rlink!=head){ tempP=head->rlink; head->rlink=tempP->rlink;//把头结点后的第一个节点从链中脱离 tempP->rlink->llink=head;//处理左指针 delete tempP; //删除(释放)脱离下来的结点 } current=NULL; //current指针恢复 }

void DblList::InsertFront(DblNode *p){ p->llink=head;//注意次序

继承与派生习题 25

p->rlink=head->rlink; head->rlink->llink=p; head->rlink=p;//最后做 }

void DblList::InsertRear(DblNode *p){ p->rlink=head;//注意次序 p->llink=head->llink; head->llink->rlink=p; head->llink=p;//最后做 }

void DblList::InsertOrder(DblNode* p){ if(head==head->llink) { p->llink=head;//注意次序 p->rlink=head->rlink; head->rlink->llink=p; head->rlink=p;//最后做 } else{ current=head->rlink; while(current!=head){ if(*current->info>*p->info) break; //找第一个比插入结点大的结点 current=current->rlink; } p->rlink=current;//注意次序 p->llink=current->llink; current->llink->rlink=p; current->llink=p;//最后做 } }

DblNode* DblList::CreatNode(){//建立新节点 current=new DblNode(); return current; }

DblNode* DblList::DeleteNode(DblNode* p){ current=head->rlink; while(current!=head&¤t!=p) current=current->rlink; if(current==head) current=NULL; else{//结点摘下 p->llink->rlink=p->rlink; p->rlink->llink=p->llink; p->rlink=p->llink=NULL; } return current; }

26

DblNode* DblList::Find(Object & obj){//对抽象类只能用“引用” current=head->rlink; while(current!=head&&*current->info!=obj) current=current->rlink; if(current==head) current=NULL; return current;//搜索成功返回该结点地址,不成功返回NULL }

void DblList::PrintList(){ current=head->rlink; while(current!=head){ current->info->Print(); current=current->rlink; } cout<DblList::Length(){ int count=0; current=head->rlink; while(current!=head){ count++; current=current->rlink; } return count; }

//ep8_9.cpp

#include \"ep8_9.h\" #include using namespace std;

class StringObject:public Object{ string sptr; public: StringObject(); StringObject(string); ~StringObject(); bool StringObject::operator>(Object & obj);//虚函数 bool StringObject::operator!=(Object & obj);//虚函数 void Print(); };

StringObject::StringObject(){sptr=\"\";}

StringObject::StringObject(string s){sptr=s;}

StringObject::~StringObject(){cout<<\"删除字符串类\"<(Object & obj){//虚函数 StringObject & temp=(StringObject &)obj;//必须转换 return sptr>temp.sptr; }

继承与派生习题 27

bool StringObject::operator!=(Object & obj){//虚函数 StringObject & temp=(StringObject &)obj;//必须转换 return sptr!=temp.sptr; }

void StringObject::Print(){cout<Linkinfo(p);//数据对象连接到结点 list1.InsertFront(P1);//向前生成list1 p=new StringObject(a[i]); P1=list2.CreatNode(); P1->Linkinfo(p); list2.InsertRear(P1);//向后生成list2 } list1.PrintList(); cout<<\"list1长度:\"<Linkinfo(p); list3.InsertOrder(P1);//升序创建list3

28

} list3.PrintList(); cout<<\"程序结束:\"<8.10 矩形法(rectangle)积分近似计算公式为:

baf(x)dxx(y0y1yn1)

x[y02(y1yn1)yn] 2x[y0yn4(y1y3yn1)2(y2y4yn2)] 3梯形法(ladder)积分近似计算公式为:

baf(x)dx辛普生法(simpson)积分近似计算公式(n为偶数)为:

baf(x)dx被积函数用派生类引入,被积函数定义为纯虚函数。

基类(integer)成员数据包括:积分上下限b和a;分区数n;步长step=(b-a)/n,积分值result。定义积分函数integerate()为虚函数,它只显示提示信息。

派生的矩形法类(rectangle)重定义integerate(),采用矩形法作积分运算。 派生的梯形法类(ladder)和辛普生法(simpson)类似。 请编程,用三种方法对下列被积函数 (1) sin(x),下限为0.0和上限为π/2; (2) exp(x),下限为0.0和上限为1.0; (3) 4.0/(1+x*x),下限为0.0和上限为1.0。 进行定积分计算,并比较积分精度。

解:使用类参数传递被积函数,因类有数据域,也可以同时传递积分上下限,可由读者进行

修改。

#include #include using namespace std; class Base{ protected:

double result,a,b,step;//Intevalue积分值,a积分下限,b积分上限 int n; public: virtual double fun(double x)=0;//被积函数声明为纯虚函数 virtual void Integerate(){ cout<<\"这里是积分函数\"<继承与派生习题 29

} void Print(){ cout.precision(15); cout<<\"积分值=\"<class Rectangle:public Base{ public: void Integerate(){ int i; step=(b-a)/n; for(i=0;i<=n;i++) result+=fun(a+step*i); result*=step; } Rectangle(double ra,double rb,int nn):Base(ra,rb,nn){} };

class Ladder:public Base{ public: void Integerate(){ int i; step=(b-a)/n; result=fun(a)+fun(b); for(i=1;iclass Simpson:public Base{ public: void Integerate(){ int i; step=(b-a)/n; result=fun(a)+fun(b); for(i=1;iclass sinR:public Rectangle{//矩形法和梯形法采用并列结构 public: sinR(double ra,double rb,int nn):Rectangle(ra,rb,nn){} double fun(double x){return sin(x);} };

30

class sinL:public Ladder{ public: sinL(double ra,double rb,int nn):Ladder(ra,rb,nn){} double fun(double x){return sin(x);} };

class expR:public Rectangle{ public: expR(double ra,double rb,int nn):Rectangle(ra,rb,nn){} double fun(double x){return exp(x);} };

class expL:public Ladder{ public: expL(double ra,double rb,int nn):Ladder(ra,rb,nn){} double fun(double x){return exp(x);} };

class otherR:public Rectangle{ public: otherR(double ra,double rb,int nn):Rectangle(ra,rb,nn){} double fun(double x){return (4.0/(1+x*x));} };

class otherL:public Ladder{ public: otherL(double ra,double rb,int nn):Ladder(ra,rb,nn){} double fun(double x){return (4.0/(1+x*x));} };

class sinS:public Simpson{//辛普生法采用层次结构 public: sinS(double ra,double rb,int nn):Simpson(ra,rb,nn){} double fun(double x){return sin(x);} };

class expS:public sinS{ public: expS(double ra,double rb,int nn):sinS(ra,rb,nn){} double fun(double x){return exp(x);} };

class otherS:public expS{ public: otherS(double ra,double rb,int nn):expS(ra,rb,nn){} double fun(double x){return (4.0/(1+x*x));} };

int main(){ Base *bp; sinR sr(0.0,3./2.0,100); bp=&sr;

继承与派生习题 31

}

bp->Integerate();//动态,可以访问派生类定义的被积函数 bp->Print();

sinL sl(0.0,3./2.0,100); bp=&sl;

bp->Integerate();//动态,可以访问派生类定义的被积函数 bp->Print();

sinS ss(0.0,3./2.0,100); bp=&ss;

bp->Integerate();//动态,在层次中选 bp->Print();

expR er(0.0,1.0,100); bp=&er;

bp->Integerate();//动态,可以访问派生类定义的被积函数 bp->Print();

expL el(0.0,1.0,100); bp=⪙

bp->Integerate();//动态,可以访问派生类定义的被积函数 bp->Print();

expS es(0.0,1.0,100); bp=&es;

bp->Integerate();//动态,在层次中选 bp->Print();

otherR or(0.0,1.0,100); bp=∨

bp->Integerate();//动态,可以访问派生类定义的被积函数 bp->Print();

otherL ol(0.0,1.0,100);//增加到也达不到辛普生法的精度 bp=&ol;

bp->Integerate();//动态,可以访问派生类定义的被积函数 bp->Print();

otherS os(0.0,1.0,100); bp=&os;

bp->Integerate();//动态,在层次中选 bp->Print(); return 0;

因篇幅问题不能全部显示,请点此查看更多更全内容

Top