VisualC++面向对象程序设计教程与实验(第二版)清华大学出版社—章答案 下载本文

内容发布更新时间 : 2024/10/25 7:29:55星期一 下面是文章的全部内容请认真阅读。

第五章

1. 什么是类的继承与派生?

继承性是面向对象程序设计的第二个重要特性,通过继承实现了数据抽象基础上的代码重用。继承是对许多问题中分层特性的一种自然描述,因而也是类的具体化和被重新利用的一种手段,它所表达的就是一种对象类之间的相交关系。它使得某类对象可以继承另外一类对象的特征和能力。继承所具有的作用有两个方面:一方面可以减少代码冗余;另一方面可以通过协调性来减少相互之间的接口和界面。通过继承方式定义的子类也称为派生类。

2. 类的三种继承方式之间的区别是什么?

类的继承方式有public(公有)继承、protected(保护)继承和private(私有)继承三种。对于不同的继承方式,会导致基类成员原来的访问属性在派生类中有所变化。表5.1列出了不同继承方式下基类成员访问属性的变化情况。

表5.1 不同继承方式下基类成员的访问属性

访问属性 继承方式 public protected private public public protected private protected protected protected 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

class Person{ protected: char m_strName[10]; int m_nSex; int m_nAge; public: Person(char *name,int age,char sex){ strcpy(m_strName, name); m_nSex= (sex=='m'?0:1 ); m_nAge = age; } void setName(char *name){ strcpy(m_strName, name); } void setSex(int sex){ m_nSex= (sex=='m'?0:1 ); } void setAge(int age){ m_nAge = age; } char * getName(){ return m_strName; } int getAge(){ return m_nAge; } int getSex(){ return m_nSex; } void ShowMe(){ cout<<\姓 名:\ cout<<\性 别:\男\女\ cout<<\年 龄:\ } };

class Teacher : public Person{ char m_strDept[20];

int m_fSalary; public: Teacher(char *name,int age,char sex,char *dept,int salary) :Person(name,age,sex){ strcpy(m_strDept, dept); m_fSalary = salary; } void ShowMe() { Person::ShowMe(); cout<<\工作单位:\ cout<<\月 薪:\ } void setSalary(int salary){ m_fSalary = salary; } int getSalary(){ return m_fSalary; } };

class Student : public Person{ char m_strID[12]; char m_strClass[12]; public: Student(char *name,int age,char sex,char *ID,char *Class) :Person(name,age,sex){ strcpy(m_strID, ID); strcpy(m_strClass, Class); } void ShowMe(){ cout<<\学 号:\ Person::ShowMe(); cout<<\班 级:\ } void setID(char * ID){ strcpy(m_strID, ID); } void setClass(char *Class){

strcpy(m_strClass, Class); } char* getID(){ return m_strID; } char* getClass(){ return m_strClass; } };

class Employee:public Person{ int m_fSalary; public: Employee(char *name,int age,char sex,int salary) :Person(name,age,sex){ m_fSalary = salary; } void setSalary(int salary){ m_fSalary = salary; } int getSalary(){ return m_fSalary; } void ShowMe(){ Person::ShowMe(); cout<<\工 资:\ } };

void main(){ // 定义三个不同类的对象 Teacher teacher1(\刘馨\计算机系\ Student std1(\刘丽\计算机03\ Employee emPloyee1(\张鑫\ //显示各类人员的属性 teacher1.ShowMe(); cout<<\