浙江理工大学信息学院
实验指导书
实验名称:类的继承机制的实现 学时安排:3
实验类别:设计性实验 实验要求:1人1组
学号:2020329621193 姓名:杨正龙
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
一、实验目的
1.掌握单继承和多重继承的概念。
2.理解不同的继承类型:public、protected和private,掌握何时使用何种继承类型。
3.掌握类层次中构造函数的定义方式和建立对象时构造和析构次序
二、实验原理介绍
通过继承机制实现对类功能的扩展,合理设计派生类的构造函数、成员函数。
三、实验设备介绍
软件需求: Visual Studio C++或Codeblocks或Dev C++或其他C++ IDE
硬件需求: 能够流畅运行C++ IDE的计算机一台。
四、实验内容
实现对第一次实验结果Elevator类的功能扩展。在Elevator类已有功能的基础上派生AdvancedElevator类。AdvancedElevator类可以实现当多人在不同楼层等待乘坐上行或下行的同一部电梯时,能够合理的根据乘坐人的需求对电梯经停的楼层进行排序。
要求:
1.为了实现上的方便性,我们假设同一组要求乘坐电梯的乘客或者都是上行,或者都是下行。
2.在主函数中对该类的功能进行测试,测试方法是首先选择在某一时间段一组要乘坐电梯的乘客是上行还是下行,然后输入组中乘客的人数及每一个乘客所在楼层和目的楼层,由AdvancedElevator类实例化后的电梯对象在运作的过程中,如果电梯是上行,则能根据乘客所在的楼层和目的楼层从下向上依次停靠;如果电梯是下行,则能根据乘客所在的楼层和目的楼层从上向下依次停靠。
3.在测试的过程中,还需要注意测试当多个用户在同一楼层或多个用户的目的楼层为同一楼层时情况的处理。
提示:
为了方便描述乘客,我们可以定义一个Person类,主要描述每一个乘客所在楼层和目的楼层。AdvancedElevator类从Elevator类继承而来,它从某一个时间段要乘坐电梯的每个乘客的信息当中提取其所在楼层和目的楼层信息,然后对它们进行排序,再由继承自基类Elevator的成员对要停靠的楼层序列依次输出。
思考(可选)
如果加入乘客的体重信息,如何实现在停靠楼层对超载信息的提示。
五、程序清单
AdvancedElevator.h
#pragma once
#include"Elevator.h"
#include "Person.h"
#include <vector>
class AdvancedElevator : public Elevator
{
public:
AdvancedElevator();
AdvancedElevator(int floor);
AdvancedElevator(int floor, int weight);
virtual ~AdvancedElevator();
void setLimitWeight(int weight);
int getLimitWeght();
void setUpButton();
void setDownButton();
void init();
void run();
protected:
int limitweight;
};
data.h
#pragma once
#ifndef DATE_H
#define DATE_H
#include <iostream>
#include<ctime>
#include<cstdlib>
#include<string>
#include<cstdio>
using namespace std;
class CDate {
int d, m, y;
const string df_s;
const string df_l;
public:
CDate(int dd, int mm = 1, int yy = 1999);
CDate();
void add_year(int n);
void add_month(int n);
void add_day(int n);
string format(string df);
int get_day() const;
int get_month() const;
int get_year() const;
};
#endif
Elevator.h
#pragma once
#define ELEVATOR_H
#define FLOOR 10
#define MS 100
#include <iostream>
#include <windows.h>
#include <stdlib.h>
#include"data.h"
using namespace std;
class Elevator
{
public:
Elevator();
virtual ~Elevator();
Elevator(int floor);
void setUpButton(); //按下上行按钮
void setDownButton(); //按下下行按钮
void setFloorNumber(int floorNumber); //根据要进入的楼层电梯开始运行,并逐层显示经过的楼层
int getCurrentFloor(); //获得当前所在楼层
void setUp(bool up);
void setDown(bool down);
void setFloor(int floor);
bool getup();
bool getdown();
int getFloor();
void err();
void init();
void memu();
void run();
protected:
int floor; //电梯总的楼层数
bool up; //是否上行,bool为布尔类型,可取值true或false
bool down; //是否下行
int currentFloor; //当前所在楼层
CDate data;
private:
void outsideopen();//电梯外开门动画
void outsideclose();//电梯外关门动画
void insideopen();//电梯内开门动画
void insideclose();//电梯内关门动画
void waitgame();//等待动画
};
Person.h
#pragma once
class Person
{
public:
Person();
Person(int ID, int u, int v);
Person(int ID, int u, int v, int w);
virtual ~Person();
void setID(int ID);
void setform(int u);
void setto(int v);
void setweight(int w);
int getID();
int getform();
int getto();
int getweight();
bool operator <(const Person& P);
protected:
private:
int PersenId; //乘客编号
int PersenForm; //乘客起点
int PersenGoto; //乘客终点
int PersenWeight;//乘客体重
};
AdvancedElevator.cpp
#include "AdvancedElevator.h"
AdvancedElevator::AdvancedElevator():Elevator(10),limitweight(200){} //构造函数 默认楼层数 默认载重
AdvancedElevator::~AdvancedElevator(){} //构造函数 自定义楼层数 默认载重
AdvancedElevator::AdvancedElevator(int floor):Elevator(floor),limitweight(200){} //构造函数 自定义楼层数 自定义载重
AdvancedElevator::AdvancedElevator(int floor,int weight):Elevator(floor),limitweight(weight){}
void AdvancedElevator::setUpButton()//按下上行按钮
{
int now=getCurrentFloor();//获取当前电梯楼层
//如果当前在顶楼不能上行
if(now==floor){
cout<<"本电梯已经到达顶楼"<<endl;
return;
}
cout<<"请输入要乘坐电梯的人数"<<endl;
int num=0;
cin >> num;
Person* person = new Person[num];
cout<<"请输入每个人所在楼层和目的楼层和此人体重"<<endl;
cout<<"当前电梯停在"<<now<<"层"<<endl;
int u,v,w;//临时记录乘客信息
int nowW=0;//存储当前电梯负载
int cnt[FLOOR + 1] = { 0 };//桶排序数组
bool vis[FLOOR + 1] = { 0 };//标记乘客是否上电梯
//in存储楼层上电梯的乘客,out存储楼层下电梯的乘客
vector<Person>in[FLOOR + 1], out[FLOOR + 1];
for(int i=0;i<num;i++){
scanf("%d%d%d",&u,&v,&w);
//判断乘客是否满足条件
while(now>=v||v>floor||v<1||u<1||u>floor||now>u||u>=v||w>limitweight){//不满足条件重新录入
if(u==v){
cout<<"您不需要坐本电梯!"<<endl;
}else if(w>limitweight){
cout<<"您体重超出荷载!"<<endl;
}else{
cout<<"您不能上行!"<<endl;
}
scanf("%d%d%d",&u,&v,&w);
}
person[i]=Person(i+1,u,v,w);
cnt[u]++;//桶排序
cnt[v]++;
in[u].push_back(person[i]);
out[v].push_back(person[i]);
}
//处理当前楼层上电梯乘客
for(int i=0,j=in[now].size();i<j;i++){
if(limitweight-nowW>=in[now][i].getweight()){
vis[in[now][i].getID()]=1;
nowW+=in[now][i].getweight();
}else{
cout<<"已超重!!"<<endl;
cout<<"第"<<in[now][i].getID()<<"位乘客不能上行!"<<endl;
}
}
//运行电梯
for(int i=now+1;i<=floor;i++){
if(cnt[i]){
up=1;
//调用父类函数setFloorNumber();
//电梯运行到下一个有乘客上下电梯的楼层
setFloorNumber(i);
up=0;
//先下后上
for(int j=0,k=out[i].size();j<k;j++){
if(vis[out[i][j].getID()]){
vis[out[i][j].getID()]=0;
nowW-=out[i][j].getweight();
}
}
for(int j=0,k=in[i].size();j<k;j++){
if(limitweight-nowW>=in[i][j].getweight()){
vis[in[i][j].getID()]=1;
nowW+=in[i][j].getweight();
}else{
cout<<"已超重!!"<<endl;
cout<<"第"<<in[i][j].getID()<<"位乘客不能上行!"<<endl;
}
}
}
}
}
void AdvancedElevator::setDownButton()//按下下行按钮
{
int now=getCurrentFloor();//获取当前电梯楼层
//如果当前在顶楼不能上行
if(now==1){
cout<<"本电梯已经到达底楼"<<endl;
return;
}
cout<<"请输入要乘坐电梯的人数"<<endl;
int num=0;
scanf("%d",&num);
Person* person = new Person[num];
cout<<"请输入每个人所在楼层和目的楼层和此人体重"<<endl;
cout<<"当前电梯停在"<<now<<"层"<<endl;
int u,v,w;//临时记录乘客信息
int nowW=0;//存储当前电梯负载
int cnt[FLOOR + 1] = { 0 };//桶排序数组
bool vis[FLOOR + 1] = { 0 };//标记乘客是否上电梯
//in存储楼层上电梯的乘客,out存储楼层下电梯的乘客
vector<Person>in[FLOOR + 1], out[FLOOR + 1];
for(int i=0;i<num;i++){
scanf("%d%d%d",&u,&v,&w);
//判断乘客是否满足条件
while(now<=v||v>floor||v<1||u<1||u>floor||now<u||u<=v||w>limitweight){//不满足条件重新录入
if(u==v){
cout<<"您不需要坐本电梯!"<<endl;
}else if(w>limitweight){
cout<<"您体重超出荷载!"<<endl;
}else{
cout<<"您不能下行!"<<endl;
}
scanf("%d%d%d",&u,&v,&w);
}
person[i]=Person(u,v,w);
cnt[u]++;//桶排序
cnt[v]++;
in[u].push_back(person[i]);
out[v].push_back(person[i]);
}
//处理当前楼层上电梯乘客
for(int i=0,j=in[now].size();i<j;i++){
if(limitweight-nowW>=in[now][i].getweight()){
vis[in[now][i].getID()]=1;
nowW+=in[now][i].getweight();
}else{
cout<<"已超重!!"<<endl;
cout<<"第"<<in[now][i].getID()<<"位乘客不能下行!"<<endl;
}
}
//运行电梯
for(int i=now-1;i>=1;i--){
if(cnt[i]){
down=1;
//调用父类函数setFloorNumber();
//电梯运行到下一个有乘客上下电梯的楼层
setFloorNumber(i);
down=0;
//先下后上
for(int j=0,k=out[i].size();j<k;j++){
if(vis[out[i][j].getID()]){
vis[out[i][j].getID()]=0;
nowW-=out[i][j].getweight();
}
}
for(int j=0,k=in[i].size();j<k;j++){
if(limitweight-nowW>=in[i][j].getweight()){
vis[in[i][j].getID()]=1;
nowW+=in[i][j].getweight();
}else{
cout<<"已超重!!"<<endl;
cout<<"第"<<in[i][j].getID()<<"位乘客不能下行!"<<endl;
}
}
}
}
}
void AdvancedElevator::setLimitWeight(int weight){//设置最大载重
limitweight=weight;
}
int AdvancedElevator::getLimitWeght(){//返回最大载重
return limitweight;
}
void AdvancedElevator::init()//重写初始化
{
Elevator::init();//调用父类初始化
cout<<endl;
cout<<"该电梯最大载重"<<getLimitWeght()<<"KG"<<endl;//增加显示最大载重
}
void AdvancedElevator::run()//封装run
{
init();
bool online=1;
while(online){
int op;
memu();
scanf("%d",&op);
switch(op){
case 1:setUpButton();break;//上行
case 2:setDownButton();break;//下行
case 3:online=0;break;//退出
default:err();break;//错误
}
system("pause");//按任意键继续...
}
}
data.cpp
#include"data.h"
CDate::CDate(int dd, int mm, int yy) :df_s("ddd"), df_l("DDD") //初始化
{
if ((mm >= 1 && mm <= 12) && (dd >= 1 && dd <= 31))
{
m = mm; d = dd; y = yy;
}
else {
m = 0; d = 0; y = 0;
cout << "the date created is wrong" << endl;
}
}
CDate::CDate() :df_s("ddd"), df_l("DDD") //初始化
{
time_t now;
time(&now);
struct tm* t_now;
t_now = localtime(&now);
y = t_now->tm_year + 1900;
m = t_now->tm_mon + 1;
d = t_now->tm_mday;
}
void CDate::add_year(int n) //加n年
{
y += n;
}
void CDate::add_month(int n) //加n月
{
m += n;
}
void CDate::add_day(int n) //加n天
{
d += n;
}
string CDate::format(string df)
{
char c_df[20];
if (df == df_s)
{
sprintf(c_df, "%d-%d-%d", y, m, d);
return string(c_df);
}
if (df == df_l)
{
sprintf(c_df, "%d年%d月%d日", y, m, d);
return string(c_df);
}
return string("");
}
int CDate::get_day() const
{
return d;
}
int CDate::get_month() const
{
return m;
}
int CDate::get_year() const
{
return y;
}
Function.cpp
#include "Elevator.h"
Elevator::Elevator() :floor(10), up(0), down(0), currentFloor(1){}
Elevator::~Elevator(){}
Elevator::Elevator(int floor) :floor(floor), up(0), down(0), currentFloor(1){}
void Elevator::setUpButton()//按下上行按钮
{
int now = getCurrentFloor(), to;
cout << "当前电梯停在" << now << "层" << endl;
cout << "请输入要进入的楼层" << endl;
scanf("%d", &to);
if (now >= to || to > floor || to < 1) {
cout << "您不能上行!" << endl;
}
else {
up = 1;
setFloorNumber(to);
up = 0;
}
}
void Elevator::setDownButton()//按下下行按钮
{
int now = getCurrentFloor(), to;
cout << "当前电梯停在" << now << "层" << endl;
cout << "请输入要进入的楼层" << endl;
scanf("%d", &to);
if (now <= to || to > floor || to < 1) {
cout << "您不能下行!" << endl;
}
else {
down = 1;
setFloorNumber(to);
down = 0;
}
}
void Elevator::setFloorNumber(int floorNumber)//根据要进入的楼层电梯开始运行,并逐层显示经过的楼层
{
if (up) {
for (int i = currentFloor; i < floorNumber; i++) {
cout << "┌───────────┬──────────┬───────┐" << endl;
cout << "│ │ │ ┌───┐ │ " << endl;
cout << "│ │ │ │ " << i << " │ │ " << endl;
cout << "│ │ │ │ ▲│ │ " << endl;
cout << "│ │ │ └───┘ │ " << endl;
cout << "│ │ │┌─────┐│ " << endl;
cout << "│ │ ││ ⑨⑩││ " << endl;
cout << "│ │ ││ ⑦⑧││ " << endl;
cout << "│ │ ││ ⑤⑥││ " << endl;
cout << "│ │ ││ ③④││ " << endl;
cout << "│ │ ││ ①②││ " << endl;
cout << "│ │ │└─────┘│ " << endl;
cout << "└───────────┴──────────┴───────┘" << endl;
Sleep(1000);
}
cout << "┌───────────┬──────────┬───────┐" << endl;
cout << "│ │ │ ┌───┐ │ " << endl;
cout << "│ │ │ │ " << floorNumber << " │ │ " << endl;
cout << "│ │ │ │ ▲│ │ " << endl;
cout << "│ │ │ └───┘ │ " << endl;
cout << "│ │ │┌─────┐│ " << endl;
cout << "│ │ ││ ⑨⑩││ " << endl;
cout << "│ │ ││ ⑦⑧││ " << endl;
cout << "│ │ ││ ⑤⑥││ " << endl;
cout << "│ │ ││ ③④││ " << endl;
cout << "│ │ ││ ①②││ " << endl;
cout << "│ │ │└─────┘│ " << endl;
cout << "└───────────┴──────────┴───────┘" << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
cout << "第" << floorNumber << "层到了" << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
}
if (down) {
for (int i = currentFloor; i > floorNumber; i--) {
cout << "┌───────────┬──────────┬───────┐" << endl;
cout << "│ │ │ ┌───┐ │ " << endl;
cout << "│ │ │ │ " << i << " │ │ " << endl;
cout << "│ │ │ │ ▼│ │ " << endl;
cout << "│ │ │ └───┘ │ " << endl;
cout << "│ │ │┌─────┐│ " << endl;
cout << "│ │ ││ ⑨⑩││ " << endl;
cout << "│ │ ││ ⑦⑧││ " << endl;
cout << "│ │ ││ ⑤⑥││ " << endl;
cout << "│ │ ││ ③④││ " << endl;
cout << "│ │ ││ ①②││ " << endl;
cout << "│ │ │└─────┘│ " << endl;
cout << "└───────────┴──────────┴───────┘" << endl;
Sleep(1000);
}
cout << "┌───────────┬──────────┬───────┐" << endl;
cout << "│ │ │ ┌───┐ │ " << endl;
cout << "│ │ │ │ " << floorNumber << " │ │ " << endl;
cout << "│ │ │ │ ▼│ │ " << endl;
cout << "│ │ │ └───┘ │ " << endl;
cout << "│ │ │┌─────┐│ " << endl;
cout << "│ │ ││ ⑨⑩││ " << endl;
cout << "│ │ ││ ⑦⑧││ " << endl;
cout << "│ │ ││ ⑤⑥││ " << endl;
cout << "│ │ ││ ③④││ " << endl;
cout << "│ │ ││ ①②││ " << endl;
cout << "│ │ │└─────┘│ " << endl;
cout << "└───────────┴──────────┴───────┘" << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_INTENSITY);
cout << "第" << floorNumber << "层到了" << endl;
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
}
currentFloor = floorNumber;
}
int Elevator::getCurrentFloor()//获得当前所在楼层
{
return currentFloor;
}
void Elevator::setUp(bool up) {
this->up = up;
}
void Elevator::setDown(bool down) {
this->down = down;
}
void Elevator::setFloor(int floor) {
this->floor = floor;
}
bool Elevator::getup() {
return up;
}
bool Elevator::getdown() {
return down;
}
int Elevator::getFloor() {
return floor;
}
void Elevator::err()
{
cout << "-----无效操作-----" << endl;
}
void Elevator::memu()
{
cout << "┌───────────┬──────────┐" << endl;
cout << "│ │ │ " << endl;
cout << "│ │ │ " << endl;
cout << "│ │ │ " << endl;
cout << "│ │ │ ┌───┐ " << endl;
cout << "│ │ │ │ ▲│ 1.上升 " << endl;
cout << "│ │ │ │ ▼│ 2.下降 " << endl;
cout << "│ │ │ └───┘ " << endl;
cout << "│ │ │ " << endl;
cout << "│ │ │ " << endl;
cout << "│ │ │ " << endl;
cout << "│ │ │ " << endl;
cout << "└───────────┴──────────┘" << endl;
}
void Elevator::init()
{
cout << "今天是" << data.format("DDD") << endl;
cout << "该电梯一共" << getFloor() << "层, 欢迎您的使用!" << endl;
}
void Elevator::run()
{
init();
bool online = 1;
while (online) {
int op;
memu();
scanf("%d", &op);
switch (op) {
case 1:setUpButton(); break;
case 2:setDownButton(); break;
case 3:online = 1; break;
default:err(); break;
}
}
}
void Elevator::outsideopen() {};
void Elevator::insideopen() {};
void Elevator::outsideclose() {};
void Elevator::insideclose() {};
void Elevator::waitgame() {};
Person.cpp
#include "Person.h"
Person::Person(){}
Person::~Person(){}
Person::Person(int ID, int u, int v) :PersenId(ID), PersenForm(u), PersenGoto(v), PersenWeight(50){}
Person::Person(int ID, int u, int v, int w) : PersenId(ID), PersenForm(u), PersenGoto(v), PersenWeight(w){}
void Person::setID(int ID) {
PersenId = ID;
}
void Person::setform(int u) {
PersenForm = u;
}
void Person::setto(int v) {
PersenGoto = v;
}
void Person::setweight(int w) {
PersenWeight = w;
}
int Person::getID() {
return PersenId;
}
int Person::getform() {
return PersenForm;
}
int Person::getto() {
return PersenGoto;
}
int Person::getweight() {
return PersenWeight;
}
bool Person::operator <(const Person& P) {//重载运算符排序
if (PersenForm == P.PersenForm)
PersenGoto < P.PersenGoto;
return PersenForm < P.PersenForm;
}
main.cpp
#include<iostream>
#include"AdvancedElevator.h"
using namespace std;
AdvancedElevator Advanced_Elevator(10, 200);
int main()
{
Advanced_Elevator.run();
return 0;
}
六、运行结果
七、实验心得
本次实验让我深刻体会了类的重要性。如果前期的基础没有做好,等到后期增加功能并实现封装时难度会大大上升,甚至之前的代码都要全部推倒重建。在实验中,通过继承机制实现了对类功能的扩展,从而设计出更多的派生类的函数,扩展了电梯的功能。如果类定义的好,那么在后期增加或者维护功能时可以事半功倍;但如果类的定义不够好不够合理,那么后期就会事倍功半。