C第5章习题参考答案.docx
《C第5章习题参考答案.docx》由会员分享,可在线阅读,更多相关《C第5章习题参考答案.docx(26页珍藏版)》请在冰豆网上搜索。
![C第5章习题参考答案.docx](https://file1.bdocx.com/fileroot1/2023-2/2/41d3cf5a-eb0e-405c-bf54-4222d42f4d2b/41d3cf5a-eb0e-405c-bf54-4222d42f4d2b1.gif)
C第5章习题参考答案
1.什么是类的继承与派生?
继承性是面向对象程序设计的第二个重要特性,通过继承实现了数据抽象基础上的代码重用。
继承是对许多问题中分层特性的一种自然描述,因而也是类的具体化和被重新利用的一种手段,它所表达的就是一种对象类之间的相交关系。
它使得某类对象可以继承另外一类对象的特征和能力。
继承所具有的作用有两个方面:
一方面可以减少代码冗余;另一方面可以通过协调性来减少相互之间的接口和界面。
通过继承方式定义的子类也称为派生类。
2.类的三种继承方式之间的区别是什么?
类的继承方式有public(公有)继承、protected(保护)继承和private(私有)继承三种。
对于不同的继承方式,会导致基类成员原来的访问属性在派生类中有所变化。
表5.1列出了不同继承方式下基类成员访问属性的变化情况。
表5.1不同继承方式下基类成员的访问属性
访问属性
继承方式
public
protected
private
public
public
protected
不可访问的
protected
protected
protected
不可访问的
private
private
private
不可访问的
说明:
该表第1列给出3种继承方式,第1行给出基类成员的3种访问属性。
其余单元格内容为基类成员在派生类中的访问属性。
从表中可以看出:
(1)基类的私有成员在派生类中均是不可访问的,它只能由基类的成员访问。
(2)在公有继承方式下,基类中的公有成员和保护成员在派生类中的访问属性不变。
(3)在保护继承方式下,基类中的公有成员和保护成员在派生类中均为保护的。
(4)在私有继承方式下,基类中的公有成员和保护成员在派生类中均为私有的。
需要注意的是:
保护成员与私有成员唯一的不同是当发生派生后,处在基类protected区的成员可被派生类直接访问,而私有成员在派生类中是不可访问的。
在同一类中私有成员和保护成员的用法完全一样。
3.派生类能否直接访问基类的私有成员?
若否,应如何实现?
派生类不能直接访问基类的私有成员。
具体实现方式:
(1)在类定义体中增加保护段
为了便于派生类的访问,可以将基类私有成员中需提供给派生类访问的部分定义为保护段成员。
保护段成员可以被它的派生类访问,但是对于外界是隐藏起来的。
这样,既方便了派生类的访问,又禁止外界对它的派生类访问。
这种方式的缺点是在公有派生的情况下,如果把成员设为保护访问控制,则为外界访问基类的保护段成员提供了机会,而三种派生方式,我们经常使用的是公有派生。
(2)将需访问基类私有成员的派生类成员函数声明为基类的友元
这样派生类中的其它成员函数均无权访问它,外界不可能通过派生新类来达到访问基类私有成员的目的。
4.派生类构造函数和析构函数的执行顺序是怎样的?
在多继承中,派生类构造函数和析构函数的执行顺序又是怎样的?
构造函数的执行顺序:
先祖先(基类)、再客人(对象成员),后自己(派生类本身)。
析构函数的执行顺序和构造函数正好严格相反:
先自己(派生类本身),再客人(对象成员),后祖先(基类)。
在多个基类之间严格按照派生类定义时从左到右的顺序来排列先后。
而析构函数的调用顺序刚好与构造函数的相反。
5.派生类的构造函数和析构函数的作用是什么?
在下面两种情况下,必须定义派生类的构造函数:
派生类本身需要构造函数;在定义派生类对象时,其相应的基类对象需调用带有参数的构造函数。
派生类对象的初始化也是通过派生类的构造函数实现的。
具体来说,就是对该类的数据成员赋初值。
派生类析构函数的功能与没有继承关系的类中析构函数的功能一样,也是在对象消亡之前进行一些必要的清理工作。
6.多继承一般应用在哪些场合?
对于多重继承,派生类可以有多个直接基类。
这时的派生类同时得到了多个已有类的特征。
7.在类的派生中为何引入虚基类?
在含有虚基类的派生类中,当创建它的对象时,构造函数的执行顺序如何?
当在多条继承路径上有一个公共的基类,在这些路径中的某几条路径汇合处,这个公共的基类就会产生多个实例(或多个副本),若想只保存这个基类的一个实例,可以将这个公共基类说明为虚基类。
从基类派生新类时,使用关键字virtual可以将基类说明成虚基类。
在多个基类之间严格按照派生类定义时从左到右的顺序来排列先后。
而析构函数的调用顺序刚好与构造函数的相反。
如果基类中有虚基类,则构造函数的调用顺序采用下列规则:
(1)虚基类的构造函数在非虚基类之前调用。
(2)若同一层次中包含多个虚基类,这些虚基类的构造函数按照他们说明的次序调用;
(3)若虚基类由非虚基类派生而来,则仍然先调用基类构造函数,再调用派生类的构造函数。
特别需要注意,当一个派生类同时有多个基类时,对于所有需要给予参数进行初始化的基类,都要显式给出基类名和参数表。
对于使用默认构造函数的基类,可以不给出类名。
同样,对于对象成员,如果是使用默认构造函数,也不需要写出对象名和参数表。
而对于单继承,就只需要写一个基类名就可以了。
8.设计一个大学的类系统,学校中有学生、教师、职员,每种人员都有自己的特性,他们之间又有相同的地方。
利用继承机制定义这个系统中的各个类及类上必须的操作。
参考程序:
#include
#include
classPerson{
protected:
charm_strName[10];
intm_nSex;
intm_nAge;
public:
Person(char*name,intage,charsex){
strcpy(m_strName,name);
m_nSex=(sex=='m'?
0:
1);
m_nAge=age;
}
voidsetName(char*name){
strcpy(m_strName,name);
}
voidsetSex(intsex){
m_nSex=(sex=='m'?
0:
1);
}
voidsetAge(intage){
m_nAge=age;
}
char*getName(){
returnm_strName;
}
intgetAge(){
returnm_nAge;
}
intgetSex(){
returnm_nSex;
}
voidShowMe(){
cout<<"姓名:
"<cout<<"性别:
"<<(m_nSex==0?
"男":
"女")<cout<<"年龄:
"<}
};
classTeacher:
publicPerson{
charm_strDept[20];
intm_fSalary;
public:
Teacher(char*name,intage,charsex,char*dept,intsalary)
:
Person(name,age,sex){
strcpy(m_strDept,dept);
m_fSalary=salary;
}
voidShowMe(){
Person:
:
ShowMe();
cout<<"工作单位:
"<cout<<"月薪:
"<}
voidsetSalary(intsalary){
m_fSalary=salary;
}
intgetSalary(){
returnm_fSalary;
}
};
classStudent:
publicPerson{
charm_strID[12];
charm_strClass[12];
public:
Student(char*name,intage,charsex,char*ID,char*Class)
:
Person(name,age,sex){
strcpy(m_strID,ID);
strcpy(m_strClass,Class);
}
voidShowMe(){
cout<<"学号:
"<Person:
:
ShowMe();
cout<<"班级:
"<}
voidsetID(char*ID){
strcpy(m_strID,ID);
}
voidsetClass(char*Class){
strcpy(m_strClass,Class);
}
char*getID(){
returnm_strID;
}
char*getClass(){
returnm_strClass;
}
};
classEmployee:
publicPerson{
intm_fSalary;
public:
Employee(char*name,intage,charsex,intsalary)
:
Person(name,age,sex){
m_fSalary=salary;
}
voidsetSalary(intsalary){
m_fSalary=salary;
}
intgetSalary(){
returnm_fSalary;
}
voidShowMe(){
Person:
:
ShowMe();
cout<<"工资:
"<}
};
voidmain(){
//定义三个不同类的对象
Teacherteacher1("刘馨",38,'m',"计算机系",3800);
Studentstd1("刘丽",20,'f',"","计算机03");
EmployeeemPloyee1("张鑫",25,'f',1500);
//显示各类人员的属性
teacher1.ShowMe();
cout<<"--------------------"<std1.ShowMe();
cout<<"--------------------"<emPloyee1.ShowMe();
//修改各类人员的属性
teacher1.setAge(40);
teacher1.setSalary(4500);
std1.setAge(21);
emPloyee1.setAge(26);
emPloyee1.setSalary(2000);
cout<<"--------------------"<cout<<"修改各类人员的属性后:
"<teacher1.ShowMe();
cout<<"--------------------"<std1.ShowMe();
cout<<"--------------------"<emPloyee1.ShowMe();
}
程序的执行结果为:
姓名:
刘馨
性别:
男
年龄:
38
工作单位:
计算机系
月薪:
3800
-------------------
学号:
姓名:
刘丽
性别:
女
年龄:
20
班级:
计算机03
-------------------
姓名:
张鑫
性别:
女
年龄:
25
工资:
1500
-------------------
修改各类人员的属性后:
姓名:
刘馨
性别:
男
年龄:
40
工作单位:
计算机系
月薪:
4500
-------------------
学号:
姓名:
刘丽
性别:
女
年龄:
21
班级:
计算机03
-------------------
姓名:
张鑫
性别:
女
年龄:
26
工资:
2000
9.假定车可分为货车和客车,客车又可分为轿车、面包车和公共汽车。
请设计相应的类层次结构。
说明:
可以把轿车、面包车和公共汽车定义为客车类的对象
参考程序:
#include
usingnamespacestd;
classvehicle//定义基类vehicle
{
public:
//公有函数成员
vehicle(intin_wheels,floatin_weight);//给数据成员初始化
intget_wheels();//获取车轮数
floatget_weight();//获取汽车重量
voidsetWeels(intwls);
voidsetWeight(floatwt);
voiddisplay(){
cout<<"车轮数:
"<<<"汽车重量:
"<}
private:
//私有数据成员
intwheels;//车轮数
floatweight;//表示汽车承重
};
vehicle:
:
vehicle(intin_wheels,floatin_weight){
wheels=in_wheels;
weight=in_weight;
}
floatvehicle:
:
get_weight(){
returnweight;
}
intvehicle:
:
get_wheels(){
returnwheels;
}
voidvehicle:
:
setWeels(intwls){
wheels=wls;
}
voidvehicle:
:
setWeight(floatwt){
weight=wt;
}
classtruck:
publicvehicle//定义货车类truck
{
private:
//新增私有数据成员
floatweight_load;//承重
public:
//新增公有成员函数
truck(intwheel,floatwt,floatwl):
vehicle(wheel,wt){
weight_load=wl;
}
floatgetLoads(){
returnweight_load;
}
voiddisplay(){
vehicle:
:
display();
cout<<"汽车承重"<}
};
//车和客车,客车又可分为轿车、面包车和公共汽车
classcar:
publicvehicle//定义客车类car
{
intpassenger_load;//新增私有数据成员,表示载客数
public:
//新增公有成员函数
car(intin_wheels,floatin_weight,intpeople=4):
vehicle(in_wheels,in_weight)
{
passenger_load=people;
}
intgetPassengers(){
returnpassenger_load;
}
voidsetPassengers(intpeople){
passenger_load=people;
}
voiddisplay(){
vehicle:
:
display();
cout<<"载客数:
"<}
};
voidmain(){
trucktruck1(8,400,);//货车
carcar1(4,20);//客车
carsaloon_car(4,10,5);//轿车
carmicrobus(6,10,18);//面包车
carbus(6,20,30);//公共汽车
//显示相关信息
truck1.display();
cout<<"---------------------"<car1.display();
cout<<"---------------------"<saloon_car.display();
cout<<"---------------------"<microbus.display();
cout<<"---------------------"<bus.display();
}
程序的运行结果:
车轮数:
8汽车重量:
400
汽车承重
---------------------
车轮数:
4汽车重量:
20
载客数:
4
---------------------
车轮数:
4汽车重量:
10
载客数:
5
---------------------
车轮数:
6汽车重量:
10
载客数:
18
---------------------
车轮数:
6汽车重量:
20
载客数:
30
10.设计一个能细分为矩形、三角形、圆形和椭圆形的“图形”类。
使用继承将这些图形分类,找出能作为基类部分的共同特征(如宽、高、中心点等)和方法(如初始化、求面积等),并看看这些图形是否能进一步划分为子类。
参考程序:
#include
usingnamespacestd;
classFigure//定义基类图形类
{
public:
//公有函数成员
Figure(intwid){width=wid;}
floatarea(){}
intgetWidth(){returnwidth;}
private:
//私有数据成员
intwidth;//宽度或半径
};
classRectangle:
publicFigure{//定义矩形类
intheight;
public:
Rectangle(intwid,inthei):
Figure(wid){
height=hei;
}
floatarea(){returngetWidth()*height;}
};
classTriangle:
publicFigure{//定义三角形类
intheight;
public:
Triangle(intwid,inthei):
Figure(wid){
height=hei;
}
floatarea(){return1.0/2*getWidth()*height;}
};
classCircle:
publicFigure{//定义圆类
public:
Circle(intwid):
Figure(wid){
}
floatarea(){return3.14*getWidth()*getWidth();}
};
voidmain(){
Rectanglerect(5,4);
Triangletri(5,4);
Circlecir(5);
cout<<"矩形的面积是:
"<<<"三角形的面积是:
"<<<"圆的面积是:
"<}
程序的运行结果为:
矩形的面积是:
20
三角形的面积是:
10
圆的面积是:
78.5
11.考虑大学的学生情况,试利用单继承来实现学生和毕业生两个类,设计相关的数据成员及函数,编程对继承情况进行测试。
参考程序:
#include
#include
classStudent//定义基类vehicle
{
public:
//公有函数成员
Student(intn,char*na,intg):
number(n),grade(g){
strcpy(name,na);
}
intgetNumber(){
returnnumber;
}
char*getName(){
returnname;
}
intgetGrade(){
returngrade;
}
voiddisplay(){
cout<<"学号:
"<<<"姓名:
"<<<"年级:
"<}
private:
//私有数据成员
intnumber;//学号
charname[20];//姓名
intgrade;//年级
};
classGraduate:
publicStudent{//定义毕业生类
chardesignSubject[20];
public:
Graduate(intn,char*na,char*deSub,intg=4):
Student(n,na,g)
{strcpy(designSubject,deSub);}
voiddisplay(){
Student:
:
display();
cout<<"设计题目:
"<}
};
voidmain(){
//创建对象
Studentli(2,"LiMing",3);
Graduatezhang(3,"ZhangGang","学生成绩管理系统");
//显示对象的相关信息
li.display();
cout<zhang.display();
}
程序的运行结果:
学号:
2
姓名:
LiMing
年级:
3
-----------------------------------
学号:
3
姓名:
ZhangGang
年级:
4
设计题目:
学生成绩管理系统
12.定义一个哺乳动物类,再由此派生出人类、狗类和猫类,这些类中均有speak()函数,观察在调用过程中,到底使用了谁的speak()函数。
参考程序:
#include
#include
classAnimal{
floatweight;
public:
voidspeak(){}
voidsetWeight(floatwt){weight=wt;}
floatgetWeight(){returnwei