【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
目录😋
实验目的
相关知识
一、类的继承关系基础概念
二、不同继承方式下对基类成员的访问控制
三、利用虚基类解决二义性问题
实验任务
实验步骤
编程要求
测试说明
通关代码
测试结果
实验目的
- 学习声明和使用类的继承关系,声明派生类
- 熟悉不同继承方式下对基类成员的访问控制
- 学习利用虚基类解决二义性问题
相关知识
为了完成本关任务,你需要掌握:
- 类的继承关系基础概念
- 不同继承方式下对基类成员的访问控制
- 利用虚基类解决二义性问题
一、类的继承关系基础概念
- 继承的定义:继承是面向对象编程中的一个重要特性,它允许创建一个新类(派生类)从一个现有类(基类)派生而来。派生类继承了基类的成员变量和成员函数,就好像孩子继承了父母的某些特征一样。这样可以实现代码的复用,减少重复代码的编写。
- 声明派生类的语法(以 C++ 为例):
基本语法是在派生类的定义中,在类名后面加上冒号和继承方式,再跟基类名。例如:
class DerivedClass : public BaseClass { // 派生类的成员 };
这里
DerivedClass
是派生类,BaseClass
是基类,public
是继承方式。除了public
,还有private
和protected
这两种继承方式。
二、不同继承方式下对基类成员的访问控制
- public 继承:
- 基类的
public
成员在派生类中仍然是public
,可以在派生类对象以及外部代码(通过派生类对象)中访问。基类的protected
成员在派生类中仍然是protected
,可以在派生类内部访问,但不能在外部代码(通过派生类对象)中访问。基类的private
成员在派生类中不可直接访问,就好像被隐藏起来了。例如,如果
BaseClass
有一个public
函数publicFunction()
,在DerivedClass
(通过public
继承自BaseClass
)中可以像这样调用:class BaseClass { public: void publicFunction() { // 函数实现 } }; class DerivedClass : public BaseClass { public: void callBaseFunction() { publicFunction(); // 可以在派生类中调用基类的public函数 } };
- private 继承:
- 基类的
public
和protected
成员在派生类中都变为private
。这意味着它们只能在派生类内部访问,外部代码(通过派生类对象)无法访问这些从基类继承来的成员。例如,对于
private
继承:class DerivedClass : private BaseClass { public: void callBaseFunction() { publicFunction(); // 可以在派生类内部调用基类的public函数 } }; // 但是在外部,以下代码是错误的 DerivedClass derivedObj; derivedObj.publicFunction(); // 无法访问,因为通过private继承,该函数在派生类中变为private
- protected 继承:
- 基类的
public
成员在派生类中变为protected
,protected
成员在派生类中仍然是protected
。这意味着这些成员可以在派生类内部以及派生类的派生类(下一层派生类)中访问,但不能被外部代码(通过派生类对象)访问。
三、利用虚基类解决二义性问题
- 二义性问题的产生:
- 当一个派生类有多个基类,并且这些基类又有共同的基类(间接基类)时,就可能产生二义性。例如,有一个类
Base
,类Derived1
和Derived2
都继承自Base
,然后有一个类MultiDerived
同时继承自Derived1
和Derived2
。如果Base
中有一个成员函数func()
,当在MultiDerived
中访问func()
时,编译器不知道应该从Derived1
还是Derived2
路径来访问这个func()
,就产生了二义性。- 虚基类的概念和作用:
- 虚基类是为了解决这种多继承中的二义性问题而引入的。在继承时将共同的基类声明为虚基类,这样在派生类中就只有一份共同基类的副本。
声明虚基类的语法(以 C++ 为例):在继承层次结构中,将共同的基类声明为虚基类,在继承时使用
virtual
关键字。例如:class Base { // 基类的成员 }; class Derived1 : virtual public Base { // 派生类的成员 }; class Derived2 : virtual public Base { // 派生类的成员 }; class MultiDerived : public Derived1, public Derived2 { // 此时在MultiDerived中访问Base的成员不会产生二义性 };
通过将
Base
声明为Derived1
和Derived2
的虚基类,在MultiDerived
中就只有一个Base
的实例,从而避免了访问Base
成员时的二义性。
实验任务
参考实验指导书第七章的实验任务4:
- 从实验 6 中的 people(人员)类派生出 student (学生)类,
添加属性:班号 char classNO[7];- 从 people 类派生出teacher(教师)类,
添加属性:职务 char principalship[11]、部门 char department[21]。- 从 student 类中派生出 graduate(研究生)类,
添加属性:专业 char subject[21]、导师 teacher adviser;- 从 graduate 类和 teacher 类派生出 TA(助教生)类,
注意虚基类的使用。重载相应的成员函数,测试这些类。(类之间的关系如下图所示。)
实验步骤
- 创建一个教师实例,姓名为Zheng Li,编号为1001,性别为Female,1978年1月1日生,身份证号为1234567890,职务为professor,部门为CST。
- 创建一个助教实例,姓名为Li Chao,编号为011401,性别为Male,1988年6月1日生,身份证号为12345619880601,职务为TA,部门为CST,班号为cst61,专业为computer science,导师为Zheng Li。
- 依次输出该助教的姓名,编号,部门,班号,专业和导师。
编程要求
根据提示,在右侧编辑器补充代码,并输出正确的值。
测试说明
平台会对你编写的代码进行测试:
预期输出:
TA name: Li Chao
No.: 011401
Department: CST
Class No.: cst61
Subject: computer science
Advisor: Zheng Li
开始你的任务吧,祝你成功!
通关代码
#include <iostream>
#include <cstring>
using namespace std;
class Date
{
public:
int year;
int month;
int day;
Date() {year = 1900; month = 1; day = 1;}
Date(int y, int m, int d) : year(y), month(m), day(d) {}
// Date(const Date& b) {year = b.year; month = b.month; day = b.day;}
};
class people
{
char name[11];
char number[7];
char sex[3];
Date birth;
char id[16];
public:
char* getName() {return name;}
char* getNumber() {return number;}
char* getSex() {return sex;}
Date getBirth() {return birth;}
char* getId() {return id;}
people() {}
people(const char* nm, const char* no, const char* gd, Date b, const char* i) : birth(b) {
strcpy(name, nm);
strcpy(number, no);
strcpy(sex, gd);
strcpy(id, i);
}
};
class teacher : virtual public people
{
char principalship[11];
char department[21];
public:
char* getPs() {return principalship;}
char* getDpm() {return department;}
teacher() {}
teacher(const char* ps, const char* dpm) {
strcpy(principalship, ps);
strcpy(department, dpm);
}
teacher(const char* nm, const char* no, const char* gd, Date b, const char* i, const char* ps, const char* dpm) : people(nm, no, gd, b, i) {
strcpy(principalship, ps);
strcpy(department, dpm);
}
};
class student : virtual public people
{
char classNO[7];
public:
char* getClassNO() {return classNO;}
student() {}
student(const char* cln) {strcpy(classNO, cln);}
student(const char* nm, const char* no, const char* gd, Date b, const char* i, const char* cln) : people(nm, no, gd, b, i) {
strcpy(classNO, cln);
}
};
class graduate : public student
{
char subject[21];
teacher adviser;
public:
char* getSubject() {return subject;}
teacher getAdviser() {return adviser;}
graduate() {}
graduate(const char* sbj, teacher adv) : adviser(adv) {strcpy(subject, sbj);}
graduate(const char* cln, const char* sbj, teacher adv) : student(cln), adviser(adv) {strcpy(subject, sbj);}
graduate(const char* nm, const char* no, const char* gd, Date b, const char* i, const char* cln, const char* sbj, teacher adv) :
student(nm, no, gd, b, i, cln), adviser(adv) {strcpy(subject, sbj);}
};
class TA : public graduate, public teacher
{
public:
TA() {}
TA(const char* nm, const char* no, const char* gd, Date b, const char* i, const char* ps, const char* dpm, const char* cln, const char* sbj, teacher adv) :
people(nm, no, gd, b, i), teacher(ps, dpm), graduate(cln, sbj, adv) {}
};
int main()
{
/********** Begin **********/
teacher ad("Zheng Li","1001","Female",Date(1978,1,1),"1234567890","professor","CST");
TA ta ("Li Chao","011401","Male",Date(1988,6,1),"12345619880601","TA","CST","cst61","computer science",ad);
/********** End **********/
cout << "TA name: " << ta.getName() << endl;
cout << "No.: " << ta.getNumber() << endl;
cout << "Department: " << ta.getDpm() << endl;
cout << "Class No.: " << ta.getClassNO() << endl;
cout << "Subject: " << ta.getSubject() << endl;
cout << "Advisor: " << ad.getName() << endl;
return 0;
}