继承性是面向对象程序设计的第二个重要特性,通过继承实现了数据抽象基础上的代码重用。继承是对许多问题中分层特性的一种自然描述,因而也是类的具体化和被重新利用的一种手段,它所表达的就是一种对象类之间的相交关系。它使得某类对象可以继承另外一类对象的特征和能力。继承所具有的作用有两个方面:一方面可以减少代码冗余;另一方面可以通过协调性来减少相互之间的接口和界面。通过继承方式定义的子类也称为派生类。
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 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<<\" 姓 名:\"< 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<<\" 学 号:\"< void setSalary(int salary){ m_fSalary = salary; } int getSalary(){ return m_fSalary; } void ShowMe(){ Person::ShowMe(); cout<<\" 工 资:\"< 姓 名:刘馨 性 别:男 年 龄:38 工作单位:计算机系 月 薪:3800 ------------------- 学 号:03016003 姓 名:刘丽 性 别:女 年 龄:20 班 级:计算机03 ------------------- 姓 名:张鑫 性 别:女 年 龄:25 工 资:1500 ------------------- 修改各类人员的属性后: 姓 名:刘馨 性 别:男 年 龄:40 工作单位:计算机系 月 薪:4500 ------------------- 学 号:03016003 姓 名:刘丽 性 别:女 年 龄:21 班 级:计算机03 ------------------- 姓 名:张鑫 性 别:女 年 龄:26 工 资:2000 9. 假定车可分为货车和客车,客车又可分为轿车、面包车和公共汽车。请设计相应的类层次结构。 说明:可以把轿车、面包车和公共汽车定义为客车类的对象 参考程序: #include class vehicle // 定义基类vehicle { public: // 公有函数成员 vehicle(int in_wheels,float in_weight); // 给数据成员初始化 int get_wheels(); // 获取车轮数 float get_weight(); // 获取汽车重量 void setWeels(int wls); void setWeight(float wt); void display(){ cout<<\"车轮数:\"< float weight; // 表示汽车承重 }; vehicle::vehicle(int in_wheels,float in_weight){ wheels = in_wheels; weight = in_weight; } float vehicle::get_weight(){ return weight; } int vehicle::get_wheels(){ return wheels; } void vehicle::setWeels(int wls){ wheels = wls; } void vehicle::setWeight(float wt){ weight = wt; } class truck:public vehicle // 定义货车类truck { private: // 新增私有数据成员 float weight_load; // 承重 public: // 新增公有成员函数 truck(int wheel,float wt,float wl):vehicle(wheel,wt){ weight_load = wl; } float getLoads(){ return weight_load; } void display(){ vehicle::display(); cout<<\"汽车承重\"< int passenger_load; // 新增私有数据成员,表示载客数 public: // 新增公有成员函数 car(int in_wheels,float in_weight,int people=4):vehicle(in_wheels,in_weight) { passenger_load = people; } int getPassengers(){ return passenger_load; } void setPassengers(int people){ passenger_load = people; } void display(){ vehicle::display(); cout<<\"载客数:\"< 车轮数:8 汽车重量:400 汽车承重100000 --------------------- 车轮数:4 汽车重量:20 载客数:4 --------------------- 车轮数:4 汽车重量:10 载客数:5 --------------------- 车轮数:6 汽车重量:10 载客数:18 --------------------- 车轮数:6 汽车重量:20 载客数:30 10.设计一个能细分为矩形、三角形、圆形和椭圆形的“图形”类。使用继承将这些图形分类,找出能作为基类部分的共同特征(如宽、高、中心点等)和方法(如初始化、求面积等),并看看这些图形是否能进一步划分为子类。 参考程序: #include class Figure // 定义基类图形类 { public: // 公有函数成员 Figure(int wid){width = wid;} float area(){} int getWidth(){return width;} private: // 私有数据成员 int width; // 宽度或半径 }; class Rectangle:public Figure{ // 定义矩形类 int height; public: Rectangle(int wid, int hei):Figure(wid){ height = hei; } float area(){return getWidth() * height;} }; class Triangle:public Figure{ // 定义三角形类 int height; public: Triangle(int wid, int hei):Figure(wid){ height = hei; } float area(){return 1.0/2* getWidth() * height;} }; class Circle:public Figure{ // 定义圆类 public: Circle(int wid):Figure(wid){ } float area(){return 3.14 * getWidth() * getWidth();} }; void main(){ Rectangle rect(5,4); Triangle tri(5,4); Circle cir(5); cout<<\"矩形的面积是:\"< 11.考虑大学的学生情况,试利用单继承来实现学生和毕业生两个类,设计相关的数据成员及函数,编程对继承情况进行测试。 参考程序: #include class Student // 定义基类vehicle { public: // 公有函数成员 Student(int n,char *na,int g):number(n),grade(g){ strcpy(name,na); } int getNumber(){ return number; } char * getName(){ return name; } int getGrade(){ return grade; } void display(){ cout<<\"学号:\"< class Graduate:public Student{ //定义毕业生类 char designSubject[20]; public: Graduate(int n,char *na,char * deSub,int g=4):Student(n,na,g) { strcpy(designSubject,deSub);} void display(){ Student::display(); cout<<\"设计题目:\"< li.display(); cout << endl<<\"-----------------------------------\" < 姓名:Li Ming 年级:3 ----------------------------------- 学号:3 姓名:Zhang Gang 年级:4 设计题目:学生成绩管理系统 12. 定义一个哺乳动物类,再由此派生出人类、狗类和猫类,这些类中均有speak()函数,观察在调用过程中,到底使用了谁的speak()函数。 参考程序: #include class Animal{ float weight; public: void speak(){} void setWeight(float wt){weight = wt;} float getWeight(){return weight;} }; class Human:public Animal{ public: void speak(){ cout<<\"说话\"< void speak(){ cout<<\"喵喵\"< void speak(){ cout<<\"汪汪\"< // 定义三个对象 Human hm; Cat cat; Dog dog; // 调用不同类的speak函数 cout<<\"人:\"; hm.speak(); cout<<\"猫:\"; cat.speak(); cout<<\"狗:\"; dog.speak(); } 程序的运行结果: 人:说话 猫:喵喵 狗:汪汪 13. 通过多重继承定义研究生类,研究生既有学生的属性,又有教师的属性。 参考程序: #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<<\" 姓 名:\"< 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<<\" 工作单位:\"< //显示各类人员的属性 teacher1.ShowMe(); cout<<\"--------------------\"< 工作单位:计算机系 月 薪:3800 -------------------- 学 号:03016003 姓 名:刘丽 性 别:女 年 龄:20 班 级:计算机03 -------------------- 学 号:003 姓 名:张鑫 性 别:女 年 龄:25 班 级:机械052 工作单位:机械系 月 薪:1000
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- baomayou.com 版权所有 赣ICP备2024042794号-6
违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务