【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】

简介: 本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括:1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码

目录😋

实验目的

相关知识

一、类的继承关系基础概念

二、不同继承方式下对基类成员的访问控制

三、利用虚基类解决二义性问题

实验任务

实验步骤

编程要求

测试说明

通关代码

测试结果


实验目的

  1. 学习声明和使用类的继承关系,声明派生类
  2. 熟悉不同继承方式下对基类成员的访问控制
  3. 学习利用虚基类解决二义性问题

相关知识

为了完成本关任务,你需要掌握:

  1. 类的继承关系基础概念
  2. 不同继承方式下对基类成员的访问控制
  3. 利用虚基类解决二义性问题

一、类的继承关系基础概念

  • 继承的定义:继承是面向对象编程中的一个重要特性,它允许创建一个新类(派生类)从一个现有类(基类)派生而来。派生类继承了基类的成员变量和成员函数,就好像孩子继承了父母的某些特征一样。这样可以实现代码的复用,减少重复代码的编写。
  • 声明派生类的语法(以 C++ 为例)

基本语法是在派生类的定义中,在类名后面加上冒号和继承方式,再跟基类名。例如:

class DerivedClass : public BaseClass {
    // 派生类的成员
};
image.gif

这里DerivedClass是派生类,BaseClass是基类,public是继承方式。除了public,还有privateprotected这两种继承方式。

二、不同继承方式下对基类成员的访问控制

  • 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函数
    }
};
image.gif
  • private 继承
  • 基类的publicprotected成员在派生类中都变为private。这意味着它们只能在派生类内部访问,外部代码(通过派生类对象)无法访问这些从基类继承来的成员。

例如,对于private继承:

class DerivedClass : private BaseClass {
public:
    void callBaseFunction() {
        publicFunction();  // 可以在派生类内部调用基类的public函数
    }
};
// 但是在外部,以下代码是错误的
DerivedClass derivedObj;
derivedObj.publicFunction();  // 无法访问,因为通过private继承,该函数在派生类中变为private
image.gif
  • protected 继承
  • 基类的public成员在派生类中变为protectedprotected成员在派生类中仍然是protected。这意味着这些成员可以在派生类内部以及派生类的派生类(下一层派生类)中访问,但不能被外部代码(通过派生类对象)访问。

三、利用虚基类解决二义性问题

  • 二义性问题的产生
  • 当一个派生类有多个基类,并且这些基类又有共同的基类(间接基类)时,就可能产生二义性。例如,有一个类Base,类Derived1Derived2都继承自Base,然后有一个类MultiDerived同时继承自Derived1Derived2。如果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的成员不会产生二义性
};
image.gif

通过将Base声明为Derived1Derived2的虚基类,在MultiDerived中就只有一个Base的实例,从而避免了访问Base成员时的二义性。


实验任务

参考实验指导书第七章的实验任务4:

  1. 从实验 6 中的 people(人员)类派生出 student (学生)类,
    添加属性:班号 char classNO[7];
  2. 从 people 类派生出teacher(教师)类,
    添加属性:职务 char principalship[11]、部门 char department[21]。
  3. 从 student 类中派生出 graduate(研究生)类,
    添加属性:专业 char subject[21]、导师 teacher adviser;
  4. 从 graduate 类和 teacher 类派生出 TA(助教生)类,
    注意虚基类的使用。重载相应的成员函数,测试这些类。

(类之间的关系如下图所示。)

image.gif 编辑

实验步骤

  1. 创建一个教师实例,姓名为Zheng Li,编号为1001,性别为Female,1978年1月1日生,身份证号为1234567890,职务为professor,部门为CST。
  2. 创建一个助教实例,姓名为Li Chao,编号为011401,性别为Male,1988年6月1日生,身份证号为12345619880601,职务为TA,部门为CST,班号为cst61,专业为computer science,导师为Zheng Li。
  3. 依次输出该助教的姓名,编号,部门,班号,专业和导师。

编程要求

根据提示,在右侧编辑器补充代码,并输出正确的值。

测试说明

平台会对你编写的代码进行测试:

预期输出:

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;
}

image.gif


测试结果

image.gif

image.gif

目录
相关文章
|
4月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
198 11
|
11月前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
309 15
|
9月前
|
监控 算法 数据处理
基于 C++ 的 KD 树算法在监控局域网屏幕中的理论剖析与工程实践研究
本文探讨了KD树在局域网屏幕监控中的应用,通过C++实现其构建与查询功能,显著提升多维数据处理效率。KD树作为一种二叉空间划分结构,适用于屏幕图像特征匹配、异常画面检测及数据压缩传输优化等场景。相比传统方法,基于KD树的方案检索效率提升2-3个数量级,但高维数据退化和动态更新等问题仍需进一步研究。未来可通过融合其他数据结构、引入深度学习及开发增量式更新算法等方式优化性能。
225 17
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
629 77
|
11月前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
619 6
|
12月前
|
算法 Serverless 数据处理
从集思录可转债数据探秘:Python与C++实现的移动平均算法应用
本文探讨了如何利用移动平均算法分析集思录提供的可转债数据,帮助投资者把握价格趋势。通过Python和C++两种编程语言实现简单移动平均(SMA),展示了数据处理的具体方法。Python代码借助`pandas`库轻松计算5日SMA,而C++代码则通过高效的数据处理展示了SMA的计算过程。集思录平台提供了详尽且及时的可转债数据,助力投资者结合算法与社区讨论,做出更明智的投资决策。掌握这些工具和技术,有助于在复杂多变的金融市场中挖掘更多价值。
460 12
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
283 19
|
12月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
10月前
|
编译器 C++ 容器
【c++11】c++11新特性(上)(列表初始化、右值引用和移动语义、类的新默认成员函数、lambda表达式)
C++11为C++带来了革命性变化,引入了列表初始化、右值引用、移动语义、类的新默认成员函数和lambda表达式等特性。列表初始化统一了对象初始化方式,initializer_list简化了容器多元素初始化;右值引用和移动语义优化了资源管理,减少拷贝开销;类新增移动构造和移动赋值函数提升性能;lambda表达式提供匿名函数对象,增强代码简洁性和灵活性。这些特性共同推动了现代C++编程的发展,提升了开发效率与程序性能。
407 12
|
8月前
|
人工智能 机器人 编译器
c++模板初阶----函数模板与类模板
class 类模板名private://类内成员声明class Apublic:A(T val):a(val){}private:T a;return 0;运行结果:注意:类模板中的成员函数若是放在类外定义时,需要加模板参数列表。return 0;
213 0