ビデオリンク: https://www.bilibili.com/video/BV1et411b73Z/この
メモ: P282-314
コンピュータルーム予約システム
1. コンピュータ室予約システムの要件
1.1 システムの紹介
- 現在、同校には仕様の異なる複数のコンピュータ室があり、使用中に頻繁に発生する「クラッシュ」現象のため、この問題を解決するためのコンピュータ室予約システムの開発を進めている。
1.2 アイデンティティの紹介
プログラムを使用するには 3 つの ID があります
- 学生代表者:コンピュータ室利用申請
- 教師: 生徒の予約リクエストを確認します
- 管理者: 生徒と教師のアカウントを作成します
1.3 コンピュータ室の紹介
パソコン室は全部で3室あります
- コンピュータルーム 1 - 最大収容人数 20 名
- コンピュータ室2 - 最大収容人数50名
- コンピュータ室3 - 最大収容人数100名
1.4 アプリケーションの紹介
- 要求された注文は管理者によって毎週クリアされます。
- 学生は翌週以内にコンピュータ室の利用を予約することができます。予約日は月曜日から金曜日までです。予約の際に予約時間帯(午前、午後)を選択する必要があります。
- 教師は予約を確認し、実際の状況に基づいて合否を評価します。
1.5 システム固有の要件
- まずログイン インターフェイスに入ります。オプションのログイン ID は次のとおりです。
- 学生代表
- 教師
- 管理者
- やめる
- 各 ID を検証する必要がある場合は、サブメニューに入ります
- 学生は学生番号、名前、ログインパスワードを入力する必要があります。
- 教師は従業員番号、名前、ログインパスワードを入力する必要があります。
- 管理者は、管理者名、ログインパスワードを入力する必要があります。
- 学生固有の機能
- 予約の申し込み—コンピュータ ルームを予約する
- 自分の予定を確認する - 自分の予定のステータスを確認する
- すべての予定を表示 - すべての予定情報と予定ステータスを表示します。
- 予約のキャンセル - 自分の予約をキャンセルします。成功した予約または検討中の予約はすべてキャンセルできます。
- ログアウト - ログアウト
- 教師の具体的な役割
- すべての予定を表示 - すべての予定情報と予定ステータスを表示します。
- 予定を確認する - 生徒の予定を確認する
- ログアウト - ログアウト
- 管理者固有の機能
- アカウントの追加 - 学生または教師のアカウントを追加するには、学生番号または教師の従業員番号が重複していないかを確認する必要があります。
- アカウントの表示 - 生徒または教師に関するすべての情報を表示することを選択できます
- コンピュータ ルームの表示 - すべてのコンピュータ ルームに関する情報を表示します。
- 予定をクリア - すべての予定記録をクリアします
- ログアウト - ログアウト
2. プロジェクトを作成する
プロジェクトを作成する手順は次のとおりです。
- 新しいプロジェクトを作成する
- 追加ファイル
2.1 プロジェクトの作成
- vs2017 を開いた後、[新しいプロジェクトの作成] をクリックして新しい C++ プロジェクトを作成します。
図に示すように:
- プロジェクト名を入力し、プロジェクトのパスを選択し、「OK」をクリックしてプロジェクトを生成します。
2.2 ファイルの追加
- ソースファイルを右クリックしてファイルを追加します
-
ファイル名を入力し、「追加」をクリックします
-
ファイルは正常に生成され、結果は以下のようになります。
3. メインメニューを作成する
機能の説明:
- ユーザーと対話するメイン メニューを設計する
3.1 メニューの実装
- メイン関数 main にメニュー プロンプトを追加します。コードは次のとおりです。
int main() {
cout << "====================== 欢迎来到传智播客机房预约系统 ====================="
<< endl;
cout << endl << "请输入您的身份" << endl;
cout << "\t\t -------------------------------\n";
cout << "\t\t| |\n";
cout << "\t\t| 1.学生代表 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2.老 师 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 3.管 理 员 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0.退 出 |\n";
cout << "\t\t| |\n";
cout << "\t\t -------------------------------\n";
cout << "输入您的选择: ";
system("pause");
return 0;
}
ランニング効果は以下の通りです。
3.2 ビルドインターフェース
- ユーザーの選択を受け入れてインターフェイスを構築する
- メインにコードを追加
int main() {
int select = 0;
while (true)
{
cout << "====================== 欢迎来到传智播客机房预约系统 =====================" << endl;
cout << endl << "请输入您的身份" << endl;
cout << "\t\t -------------------------------\n";
cout << "\t\t| |\n";
cout << "\t\t| 1.学生代表 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2.老 师 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 3.管 理 员 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0.退 出 |\n";
cout << "\t\t| |\n";
cout << "\t\t -------------------------------\n";
cout << "输入您的选择: ";
cin >> select; //接受用户选择
switch (select)
{
case 1: //学生身份
break;
case 2: //老师身份
break;
case 3: //管理员身份
break;
case 0: //退出系统
break;
default:
cout << "输入有误,请重新选择!" << endl;
system("pause");
system("cls");
break;
}
}
system("pause");
return 0;
}
テストします。0、1、2、3 を入力してインターフェイスに戻ります。他の入力を入力すると、入力が間違っているというプロンプトが表示されます。画面をクリアして、もう一度選択してください。
効果は次の図に示すとおりです。
この時点で、インターフェースが構築されます
4. 終了機能の実装
4.1 終了関数の実装
main 関数ブランチ 0 オプションに、プログラムを終了するコードを追加します。
cout << "欢迎下一次使用"<<endl;
system("pause");
return 0;
4.2 exit 関数のテスト
プログラムを実行すると、次のような効果が得られます。
この時点で、出口プログラム機能が実装されます。
5.アイデンティティクラスの作成
5.1 ID の基本クラス
- システム全体には、生徒の代表、教師、管理者の 3 つの ID があります。
- 3 つの ID には独自の共通点と特性があるため、3 つの ID を ID 基底クラスID に抽象化できます。
- ヘッダー ファイルの下に Identity.h ファイルを作成します。
次のコードをIdentity.hに追加します。
#pragma once //防止头文件重复包含
#include<iostream>
using namespace std;
//身份抽象类
class Identity
{
public:
//操作菜单 纯虚函数
virtual void operMenu() = 0;
string m_Name; //用户名
string m_Pwd; //密码
};
効果は次の図に示すとおりです。
5.2 学生カテゴリー
5.2.1 機能分析
-
Student クラスの主な機能は、クラス内のメンバー関数を通じて予約ラボの操作を実装することです。
-
学生カテゴリーの主な機能は次のとおりです。
- 生徒の操作のためのメニューインターフェイスを表示します
- 予約をリクエストする
- 自分の予約を表示する
- すべての予定を表示
- 予約をキャンセルする
5.2.2 クラスの作成
- ヘッダー ファイルとソース ファイルの下にstudent.h ファイルとstudent.cpp ファイルを作成します。
次のコードをStudent.hに追加します。
#pragma once
#include<iostream>
using namespace std;
#include "identity.h"
//学生类
class Student :public Identity
{
public:
//默认构造
Student();
//有参构造(学号、姓名、密码)
Student(int id, string name, string pwd);
//菜单界面
virtual void operMenu();
//申请预约
void applyOrder();
//查看我的预约
void showMyOrder();
//查看所有预约
void showAllOrder();
//取消预约
void cancelOrder();
//学生学号
int m_Id;
};
次のコードをstudent.cppに追加します。
#include "student.h"
//默认构造
Student::Student()
{
}
//有参构造(学号、姓名、密码)
Student::Student(int id, string name, string pwd)
{
}
//菜单界面
void Student::operMenu()
{
}
//申请预约
void Student::applyOrder()
{
}
//查看我的预约
void Student::showMyOrder()
{
}
//查看所有预约
void Student::showAllOrder()
{
}
//取消预约
void Student::cancelOrder()
{
}
5.3 教師カテゴリー
5.3.1 機能分析
-
教師クラスの主な機能は、生徒の予定を確認して確認することです。
-
教師カテゴリの主な機能は次のとおりです。
-
教師が操作するメニューインターフェースを表示します
-
すべての予定を表示
-
予約の確認
-
5.3.2 クラスの作成
- ヘッダー ファイルとソース ファイルの下に Teacher.h および Teacher.cpp ファイルを作成します。
次のコードをTeacher.hに追加します。
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
#include "identity.h"
class Teacher :public Identity
{
public:
//默认构造
Teacher();
//有参构造 (职工编号,姓名,密码)
Teacher(int empId, string name, string pwd);
//菜单界面
virtual void operMenu();
//查看所有预约
void showAllOrder();
//审核预约
void validOrder();
int m_EmpId; //教师编号
};
- 次のコードをTeacher.cppに追加します。
#include"teacher.h"
//默认构造
Teacher::Teacher()
{
}
//有参构造 (职工编号,姓名,密码)
Teacher::Teacher(int empId, string name, string pwd)
{
}
//菜单界面
void Teacher::operMenu()
{
}
//查看所有预约
void Teacher::showAllOrder()
{
}
//审核预约
void Teacher::validOrder()
{
}
5.4 管理者クラス
5.4.1 機能分析
-
管理者クラスの主な機能は、生徒と教師のアカウントの管理、コンピューター ルーム情報の表示、予約記録のクリアです。
-
管理者クラスの主な機能は次のとおりです。
-
管理者が操作するためのメニューインターフェースを表示します
-
アカウントを追加する
-
アカウントをみる
-
コンピュータ室の情報を見る
-
予約記録をクリアする
-
5.4.2 クラスの作成
- ヘッダー ファイルとソース ファイルの下に、manager.h および manager.cpp ファイルを作成します。
次のコードを manager.h に追加します。
#pragma once
#include<iostream>
using namespace std;
#include "identity.h"
class Manager :public Identity
{
public:
//默认构造
Manager();
//有参构造 管理员姓名,密码
Manager(string name, string pwd);
//选择菜单
virtual void operMenu();
//添加账号
void addPerson();
//查看账号
void showPerson();
//查看机房信息
void showComputer();
//清空预约记录
void cleanFile();
};
- 次のコードをmanager.cppに追加します。
#include "manager.h"
//默认构造
Manager::Manager()
{
}
//有参构造
Manager::Manager(string name, string pwd)
{
}
//选择菜单
void Manager::operMenu()
{
}
//添加账号
void Manager::addPerson()
{
}
//查看账号
void Manager::showPerson()
{
}
//查看机房信息
void Manager::showComputer()
{
}
//清空预约记录
void Manager::cleanFile()
{
}
この時点で、すべての ID クラスが作成され、その結果は次のようになります。
6. ログインモジュール
6.1 グローバルファイルの追加
機能の説明:
- 異なる ID では異なるファイル操作が使用される場合があり、すべてのファイル名を 1 つのグローバル ファイルに定義できます。
- ヘッダー ファイルにglobalFile.hファイルを追加します
- そして、次のコードを追加します。
#pragma once
//管理员文件
#define ADMIN_FILE "admin.txt"
//学生文件
#define STUDENT_FILE "student.txt"
//教师文件
#define TEACHER_FILE "teacher.txt"
//机房信息文件
#define COMPUTER_FILE "computerRoom.txt"
//订单文件
#define ORDER_FILE "order.txt"
そして、これらのファイルを同じディレクトリに作成します
6.2 ログイン関数のカプセル化
機能の説明:
- ユーザーの選択に応じて異なる ID でログインします
予約システムの .cpp ファイルにグローバル関数を追加します。void LoginIn(string fileName, int type)
パラメータ:
- fileName — 操作対象のファイル名
- type — ログイン ID (1 は学生を表し、2 は教師を表し、3 は管理者を表します)
次のコードを LoginIn に追加します。
#include "globalFile.h"
#include "identity.h"
#include <fstream>
#include <string>
//登录功能 参数1 操作文件名 参数2 操作身份类型
void LoginIn(string fileName, int type)
{
//父类指针
//用于登录成功之后,进去会创建一个对象出来,对象是老师,学生还是管理员?
//利用多态,用父类指针去指向子类对象
Identity * person = NULL;
//读文件
ifstream ifs;
ifs.open(fileName, ios::in);
//判断文件是否存在
if (!ifs.is_open()) //ifs.is_open()返回true就是存在,取反就是不存在
{
cout << "文件不存在" << endl;
ifs.close();
return;
}
//准备接受用户的信息
int id = 0;
string name;
string pwd;
//判断身份
if (type == 1) //学生登录
{
cout << "请输入你的学号" << endl;
cin >> id;
}
else if (type == 2) //教师登录
{
cout << "请输入你的职工号" << endl;
cin >> id;
}
cout << "请输入用户名:" << endl;
cin >> name;
cout << "请输入密码: " << endl;
cin >> pwd;
if (type == 1)
{
//学生登录验证
}
else if (type == 2)
{
//教师登录验证
}
else if(type == 3)
{
//管理员登录验证
}
cout << "验证登录失败!" << endl;
system("pause");
system("cls");
return;
}
- main 関数のさまざまなブランチで、さまざまなログイン インターフェイスを入力します。
6.3 学生ログインの実装
テスト用に 2 つの学生情報を Student.txt ファイルに追加します。
情報を追加します:
1 张三 123
2 李四 123456
で:
- 最初の列は学生番号を表します
- 2 列目は生徒の名前を表します
- 3 列目はパスワードを表します
レンダリング:
次のコードを Login 関数の Student ブランチに追加して、学生のIDを確認します。
//学生登录验证
int fId; //从文件中读取的id号
string fName; //从文件中读取的姓名
string fPwd; //从文件中读取的密码
while (ifs >> fId && ifs >> fName && ifs >> fPwd) //读的时候 只要碰到空格就会结束
{
if (id == fId && name == fName && pwd == fPwd)
{
cout << "学生验证登录成功!" << endl;
system("pause");
system("cls");
person = new Student(id, name, pwd);
//进入学生身份的子菜单
return;
}
}
コードレンダリングを追加する
テスト:
6.4 教師ログインの実装
テスト用に教師情報を Teacher.txt ファイルに追加します。
情報を追加します:
1 老王 123
で:
- 最初の列は教師の従業員番号を表します
- 2列目は教師の名前を表します
- 3 列目はパスワードを表します
レンダリング:
次のコードを Login 関数の Teacher ブランチに追加して、教師の ID を確認します。
//教师登录验证
int fId;
string fName;
string fPwd;
while (ifs >> fId && ifs >> fName && ifs >> fPwd)
{
if (id == fId && name == fName && pwd == fPwd)
{
cout << "教师验证登录成功!" << endl;
system("pause");
system("cls");
person = new Teacher(id, name, pwd);
return;
}
}
コードレンダリングを追加する
テスト:
6.5 管理者ログインの実装
admin.txt ファイルに管理者情報を追加します。管理者は 1 人だけなので、この場合は管理者を追加する機能はありません。
情報を追加します:
admin 123
その内: はadmin
管理者のユーザー名を表し、123
管理者のパスワードを表します
レンダリング:
次のコードを Login 関数の管理者ブランチに追加して、管理者の ID を確認します。
//管理员登录验证
string fName;
string fPwd;
while (ifs >> fName && ifs >> fPwd)
{
if (name == fName && pwd == fPwd)
{
cout << "验证登录成功!" << endl;
//登录成功后,按任意键进入管理员界面
system("pause");
system("cls");
//创建管理员对象
person = new Manager(name,pwd);
return;
}
}
追加された効果は図のとおりです。
テストの効果は次の図に示すとおりです。
この時点で、すべての ID のログイン機能が完全に実装されました。
7. 管理者モジュール
7.1 管理者のログインとログアウト
7.1.1 コンストラクター
- Manager クラスのコンストラクターで、管理者情報を初期化するコードは次のとおりです。
//有参构造
Manager::Manager(string name, string pwd)
{
//初始化管理员信息
this->m_Name = name;
this->m_Pwd = pwd;
}
7.1.2 管理者サブメニュー
- コンピュータ室予約 system.cppに、ユーザーが管理者としてログインするときに、管理者メニュー インターフェイスを追加します
- さまざまなブランチを提供する
- アカウントを追加する
- アカウントをみる
- コンピューター室を見る
- 予約をクリアする
- ログアウト
- ログアウト機能の実装
グローバル関数 を追加しますvoid managerMenu(Identity * &manager)
。コードは次のとおりです。
//管理员菜单
/*
1、这里出现了指针的引用这个东西,也不难理解,把identity*当做一个类,类名后加&,就是应用这个类的对象,所以这里是以引用的方式来接收identity类的指针实参。
2、加不加&的区别就在于,不加,重新开辟空间并创建了一个指名为manager的指针,这个指针内部存放的数据是对实参数据的拷贝(拷贝了一块地址编号)
3、加了&,如果不考虑引用的本质,那么就相当于给实参指针起了第二个名字,叫做manager,我们可以通过manager这个名字直接去调用实参。
4、这里还要再补上的一个知识点就是,形参是n级指针,实参也是n级指针时,形参指针不会指向实参,而是进行对实参的拷贝,如果想让指针指向指针,那么形参指针需要比实参指针高一级
*/
void managerMenu(Identity * &manager)
{
while (true)
{
//调用管理员子菜单
manager->operMenu();
//将父类指针 转为子类指针 可以调用子类里其他接口
Manager* man = (Manager*)manager;
int select = 0;
cin >> select;
if (select == 1) //添加账号
{
cout << "添加账号" << endl;
man->addPerson();
}
else if (select == 2) //查看账号
{
cout << "查看账号" << endl;
man->showPerson();
}
else if (select == 3) //查看机房
{
cout << "查看机房" << endl;
man->showComputer();
}
else if (select == 4) //清空预约
{
cout << "清空预约" << endl;
man->cleanFile();
}
else
{
delete manager; //销毁掉堆区对象
cout << "注销成功" << endl;
system("pause");
system("cls");
return;
}
}
}
7.1.3 メニュー機能の実装
- メンバー関数を実装するコードは
void Manager::operMenu()
次のとおりです。
//选择菜单
void Manager::operMenu()
{
cout << "欢迎管理员:"<<this->m_Name << "登录!" << endl;
cout << "\t\t ---------------------------------\n";
cout << "\t\t| |\n";
cout << "\t\t| 1.添加账号 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2.查看账号 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 3.查看机房 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 4.清空预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0.注销登录 |\n";
cout << "\t\t| |\n";
cout << "\t\t ---------------------------------\n";
cout << "请选择您的操作: " << endl;
}
7.1.4 インターフェースのドッキング
- 管理者が正常にログインすると、管理者サブメニュー インターフェイスが呼び出されます。
- 管理者ログイン検証ブランチにコードを追加します。
//进入管理员子菜单
managerMenu(person);
次のような効果を追加します。
ドッキングをテストします。結果は以下のようになります。
ログイン成功
ログアウト:
この時点で、管理者は正常にログインおよびログアウトできるようになります。
7.2 アカウントの追加
機能の説明:
- 学生または教師用の新しいアカウントを追加する
機能要件:
- 追加する場合、学籍番号と教職員番号を重複して入力することはできません。
7.2.1 追加機能の実装
Manager のaddPersonメンバー関数には、新しいアカウントを追加する機能が実装されており、コードは次のとおりです。
//添加账号
void Manager::addPerson()
{
cout << "请输入添加账号的类型" << endl;
cout << "1、添加学生" << endl;
cout << "2、添加老师" << endl;
string fileName; //操作文件名
string tip; //提示id号
ofstream ofs; //文件操作对象
int select = 0;
cin >> select;
if (select == 1)
{
//添加的是学生
fileName = STUDENT_FILE;
tip = "请输入学号: ";
}
else
{
//添加的是老师
fileName = TEACHER_FILE;
tip = "请输入职工编号:";
}
//利用追加的方式 写文件
ofs.open(fileName, ios::out | ios::app); //out方式写文件,并且app追加的方式写
int id; //学号 //职工号
string name; //姓名
string pwd; //密码
cout <<tip << endl;
cin >> id;
cout << "请输入姓名: " << endl;
cin >> name;
cout << "请输入密码: " << endl;
cin >> pwd;
//向文件中去添加数据
ofs << id << " " << name << " " << pwd << " " << endl;
cout << "添加成功" << endl;
system("pause");
system("cls");
ofs.close();
}
学生の追加をテストします。
生徒ファイルにメッセージが正常に追加されました
教師の追加をテストします。
教師ファイルにメッセージが正常に追加されました
7.2.2 重複排除操作
機能の説明: 新しいアカウントを追加するときに、それが重複する学生番号または重複する教師または職員番号である場合、プロンプトは正しくありません。
7.2.2.1 情報の読み取り
- 重複したアカウントを削除するには、検出される前に、まず生徒と教師のアカウント情報をプログラムに取得する必要があります。
- manager.h に、学生と教師の情報を保存する 2 つのコンテナを追加します。
- 新しいメンバー関数を追加して
void initVector()
コンテナーを初期化する
//初始化容器
void initVector();
//学生容器
vector<Student> vStu;
//教师容器
vector<Teacher> vTea;
図に示すように場所を追加します。
Manager のパラメーター化されたコンストラクターで、現在の生徒と教師の情報を取得します。
コードは以下のように表示されます。
void Manager::initVector()
{
//确保容器是清空状态
vStu.clear();
vTea.clear();
//读取学生文件中信息
ifstream ifs;
ifs.open(STUDENT_FILE, ios::in);
if (!ifs.is_open())
{
cout << "文件读取失败" << endl;
return;
}
Student s;
while (ifs >> s.m_Id && ifs >> s.m_Name && ifs >> s.m_Pwd)
{
vStu.push_back(s);
}
cout << "当前学生数量为: " << vStu.size() << endl;
ifs.close(); //学生初始化
//读取老师文件信息
ifs.open(TEACHER_FILE, ios::in);
Teacher t;
while (ifs >> t.m_EmpId && ifs >> t.m_Name && ifs >> t.m_Pwd)
{
vTea.push_back(t);
}
cout << "当前教师数量为: " << vTea.size() << endl;
ifs.close();
}
パラメータ化されたコンストラクタで、初期化コンテナ関数を呼び出します。
//有参构造
Manager::Manager(string name, string pwd)
{
this->m_Name = name;
this->m_Pwd = pwd;
//初始化容器 获取到所有文件中 学生、老师信息
this->initVector();
}
テストしてコードを実行すると、テスト コードが現在の生徒と教師の数を取得していることがわかります。
7.2.2.2 重複排除機能のカプセル化
manager.h ファイルにメンバー関数を追加します。 bool checkRepeat(int id, int type);
//检测重复 参数:(传入id,传入类型) 返回值:(true 代表有重复,false代表没有重复)
bool checkRepeat(int id, int type);
manager.cpp ファイルにメンバー関数を実装する bool checkRepeat(int id, int type);
bool Manager::checkRepeat(int id, int type)
{
if (type == 1)
{
for (vector<Student>::iterator it = vStu.begin(); it != vStu.end(); it++)
{
if (id == it->m_Id)
{
return true;
}
}
}
else
{
for (vector<Teacher>::iterator it = vTea.begin(); it != vTea.end(); it++)
{
if (id == it->m_EmpId)
{
return true;
}
}
}
return false;
}
7.2.2.3 重複排除操作の追加
生徒番号や教員番号を追加する際は、重複していないか確認してください。コードは次のとおりです。
string errorTip; //重复错误提示
if (select == 1)
{
fileName = STUDENT_FILE;
tip = "请输入学号: ";
errorTip = "学号重复,请重新输入";
}
else
{
fileName = TEACHER_FILE;
tip = "请输入职工编号:";
errorTip = "职工号重复,请重新输入";
}
ofs.open(fileName, ios::out | ios::app);
int id;
string name;
string pwd;
cout <<tip << endl;
while (true)
{
cin >> id;
bool ret = this->checkRepeat(id, select);
if (ret) //有重复
{
cout << errorTip << endl;
}
else
{
break;
}
}
コードの場所は次の図に示すとおりです。
検出効果:
7.2.2.4 バグの解決
バグの説明:
- 重複したアカウントは検出できますが、新しく追加されたアカウントはコンテナ内で更新されていないため、検出されません。
- その結果、新しく追加されたアカウントの学生番号または従業員番号は、再度追加するときに引き続き繰り返すことができます。
解決:
- 新しいアカウントが追加されるたびにコンテナを再初期化する
追加したら、次のコードを追加します。
//调用初始化容器接口,重新获取文件中的数据
this->initVector();
場所は写真の通りです。
もう一度テストしてください。新しく追加されたアカウントは再度追加されません。
7.3 アカウントの表示
機能説明:生徒情報または教師情報の表示
7.3.1 表示機能の実装
Manager のshowPersonメンバー関数には、アカウント表示機能が実装されており、コードは次のとおりです。
void printStudent(Student & s)
{
cout << "学号: " << s.m_Id << " 姓名: " << s.m_Name << " 密码:" << s.m_Pwd << endl;
}
void printTeacher(Teacher & t)
{
cout << "职工号: " << t.m_EmpId << " 姓名: " << t.m_Name << " 密码:" << t.m_Pwd << endl;
}
void Manager::showPerson()
{
cout << "请选择查看内容:" << endl;
cout << "1、查看所有学生" << endl;
cout << "2、查看所有老师" << endl;
int select = 0;
cin >> select;
if (select == 1)
{
//查看学生
cout << "所有学生信息如下: " << endl;
for_each(vStu.begin(), vStu.end(), printStudent);
}
else
{
//查看老师
cout << "所有老师信息如下: " << endl;
for_each(vTea.begin(), vTea.end(), printTeacher);
}
system("pause");
system("cls");
}
7.3.2 テスト
生徒の成績を確認するためのテスト
教師の効果を確認するテスト
以上でアカウント表示機能が完了する。
7.4 コンピュータ室を確認する
7.4.1 コンピュータ室情報の追加
案件要件では、コンピュータ室は 3 室あり、第 1 室は 20 台、第 2 室は 50 台、第 3 室は 100 台となっています。
情報をcomputerRoom.txtに入力できます。
7.4.2 コンピュータ室クラスの創設
ヘッダー ファイルの下に、新しいファイルcomputerRoom.h を作成します。
そして、次のコードを追加します。
#pragma once
#include<iostream>
using namespace std;
//机房类
class ComputerRoom
{
public:
int m_ComId; //机房id号
int m_MaxNum; //机房最大容量
};
7.4.3 コンピュータ室情報の初期化
Manager クラスの下に、コンピューター ルームの情報を保存するコンピューター ルームのコンテナーを追加します。
//机房容器
vector<ComputerRoom> vCom;
Manager のパラメーター化コンストラクターに次のコードを追加して、コンピューター ルーム情報を初期化します。
//获取机房信息
ifstream ifs;
ifs.open(COMPUTER_FILE, ios::in);
ComputerRoom c;
while (ifs >> c.m_ComId && ifs >> c.m_MaxNum)
{
vCom.push_back(c);
}
cout << "当前机房数量为: " << vCom.size() << endl;
ifs.close();
場所は写真の通りです。
現在のバージョンの計算機室情報は変更されないため、将来的に変更機能が発生した場合は、メンテナンスを容易にするために関数にカプセル化するのが最善です。
7.4.4 コンピュータ室情報の表示
Manager クラスの showComputer メンバー関数に次のコードを追加します。
//查看机房信息
void Manager::showComputer()
{
cout << "机房信息如下: " << endl;
for (vector<ComputerRoom>::iterator it = vCom.begin(); it != vCom.end(); it++)
{
cout << "机房编号: " << it->m_ComId << " 机房最大容量: " << it->m_MaxNum << endl;
}
system("pause");
system("cls");
}
コンピューター室の情報を表示する機能をテストします。
7.5 予約のクリア
機能の説明:
order.txt
生成された予定ファイルをクリアします
7.5.1 クリア機能の実装
次のコードを Manager の cleanFile メンバー関数に追加します。
//清空预约记录
void Manager::cleanFile()
{
ofstream ofs(ORDER_FILE, ios::trunc); //trunc方式打开,如果文件存在,就会删干净再重新创建。侧面表示文件清空。
ofs.close();
cout << "清空成功!" << endl;
system("pause");
system("cls");
}
クリアをテストするには、任意に order.txt に情報を書き込み、cleanFile を呼び出してファイル インターフェイスをクリアし、ファイルがきれいにクリアされたかどうかを確認します。
8. 学生モジュール
8.1 学生のログインとログアウト
8.1.1 コンストラクター
- Student クラスのコンストラクターで、生徒情報を初期化します。コードは次のとおりです。
//有参构造(学号、姓名、密码)
Student::Student(int id, string name, string pwd)
{
//初始化属性
this->m_Id = id;
this->m_Name = name;
this->m_Pwd = pwd;
}
8.1.2 管理者サブメニュー
- コンピュータ室予約 system.cpp で、ユーザーが学生としてログインするときに、学生メニュー インターフェイスを追加します。
- さまざまなブランチを提供する
- 予約をリクエストする
- 予約を表示する
- すべての予定を表示
- 予約をキャンセルする
- ログアウト
- ログアウト機能の実装
次のようにグローバル関数void studentMenu(Identity * &manager)
コードを追加します。
//学生菜单
void studentMenu(Identity * &student)
{
while (true)
{
//调用学生子菜单
student->operMenu();
Student* stu = (Student*)student;
int select = 0;
cin >> select;
if (select == 1) //申请预约
{
stu->applyOrder();
}
else if (select == 2) //查看自身预约
{
stu->showMyOrder();
}
else if (select == 3) //查看所有预约
{
stu->showAllOrder();
}
else if (select == 4) //取消预约
{
stu->cancelOrder();
}
else
{
delete student;
cout << "注销成功" << endl;
system("pause");
system("cls");
return;
}
}
}
8.1.3 メニュー機能の実装
- メンバー関数を実装するコードは
void Student::operMenu()
次のとおりです。
//菜单界面
void Student::operMenu()
{
cout << "欢迎学生代表:" << this->m_Name << "登录!" << endl;
cout << "\t\t ----------------------------------\n";
cout << "\t\t| |\n";
cout << "\t\t| 1.申请预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2.查看我的预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 3.查看所有预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 4.取消预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0.注销登录 |\n";
cout << "\t\t| |\n";
cout << "\t\t ----------------------------------\n";
cout << "请选择您的操作: " << endl;
}
8.1.4 インターフェースのドッキング
- 学生がログインに成功すると、学生のサブメニュー インターフェイスが呼び出されます。
- 学生ログイン ブランチにコードを追加します。
//进入学生子菜单
studentMenu(person);
追加された効果は図のとおりです。
ドッキングをテストします。結果は以下のようになります。
ログイン検証に合格しました:
学生サブメニュー:
ログアウト:
8.2 予約の申し込み
8.2.1 コンピュータ室情報の取得
- 学生は予約申請の際にコンピュータ室の情報を見ることができるので、コンピュータ室の情報を学生に知らせる必要があります。
次のように、student.h に新しいメンバー関数を追加します。
//机房容器
vector<ComputerRoom> vCom;
次のコードを学生のパラメータ化されたコンストラクターに追加します。
//获取机房信息
ifstream ifs;
ifs.open(COMPUTER_FILE, ios::in);
ComputerRoom c;
while (ifs >> c.m_ComId && ifs >> c.m_MaxNum)
{
//将读取的信息放入容器中
vCom.push_back(c);
}
ifs.close();
追加の場所は次の図に示すとおりです。
この時点で、すべてのコンピューター室の情報が vCom コンテナーに保存されます。
8.2.2 予約機能の実装
Student.cpp にメンバー関数を実装するvoid Student::applyOrder()
//申请预约
void Student::applyOrder()
{
cout << "机房开放时间为周一至周五!" << endl;
cout << "请输入申请预约的时间:" << endl;
cout << "1、周一" << endl;
cout << "2、周二" << endl;
cout << "3、周三" << endl;
cout << "4、周四" << endl;
cout << "5、周五" << endl;
int date = 0; //日期
int interval = 0; //时间段
int room = 0; //机房编号
while (true)
{
cin >> date;
if (date >= 1 && date <= 5)
{
break;
}
cout << "输入有误,请重新输入" << endl;
}
cout << "请输入申请预约的时间段:" << endl;
cout << "1、上午" << endl;
cout << "2、下午" << endl;
while (true)
{
cin >> interval;
if (interval >= 1 && interval <= 2)
{
break;
}
cout << "输入有误,请重新输入" << endl;
}
cout << "请选择机房:" << endl;
for(int i = 0;i < vCom.size();i++){
cout << vCom[i].m_ComId << "号机房容量为:" << vCom[i].m_MaxNum << endl;
}
//cout << "1号机房容量:" << vCom[0].m_MaxNum << endl;
//cout << "2号机房容量:" << vCom[1].m_MaxNum << endl;
//cout << "3号机房容量:" << vCom[2].m_MaxNum << endl;
while (true)
{
cin >> room;
if (room >= 1 && room <= 3)
{
break;
}
cout << "输入有误,请重新输入" << endl;
}
cout << "预约成功!审核中" << endl;
ofstream ofs(ORDER_FILE, ios::app);
ofs << "date:" << date << " ";
ofs << "interval:" << interval << " ";
ofs << "stuId:" << this->m_Id << " ";
ofs << "stuName:" << this->m_Name << " ";
ofs << "roomId:" << room << " ";
ofs << "status:" << 1 << endl;
ofs.close();
system("pause");
system("cls");
}
プログラムを実行してコードをテストします。
order.txt ファイルに次のコンテンツを生成します。
8.3 予約の表示
8.3.1 予約クラスの作成
機能の説明: 予定レコードを表示する場合、表示するファイルからすべてのレコードを取得し、レコードを管理および更新するための予定クラスを作成する必要があります。
orderFile.h ファイルとorderFile.cppファイルをそれぞれヘッダー ファイルとソース ファイルの下に作成します。
次のコードを orderFile.h に追加します。
#pragma once
#include<iostream>
using namespace std;
#include <map>
#include "globalFile.h"
class OrderFile
{
public:
//构造函数
OrderFile();
//更新预约记录
void updateOrder();
//记录的容器 key --- 记录的条数 value --- 具体记录的键值对信息
map<int, map<string, string>> m_orderData;
//预约记录条数
int m_Size;
};
コンストラクター内のすべての情報を取得し、コンテナーに保存します。次のコードを追加します。
//构造函数
OrderFile::OrderFile()
{
ifstream ifs;
ifs.open(ORDER_FILE, ios::in);
string date; //日期
string interval; //时间段
string stuId; //学生编号
string stuName; //学生姓名
string roomId; //机房编号
string status; //预约状态
this->m_Size = 0; //预约记录个数
while (ifs >> date && ifs >> interval && ifs >> stuId && ifs >> stuName && ifs >> roomId && ifs >> status)
{
//测试代码
/*
cout << date << endl;
cout << interval << endl;
cout << stuId << endl;
cout << stuName << endl;
cout << roomId << endl;
cout << status << endl;
*/
//date:1111
string key;
string value;
map<string, string> m;
int pos = date.find(":"); //4 date:1111
if (pos != -1)
{
key = date.substr(0, pos);
value = date.substr(pos + 1, date.size() - pos -1); //size=9 size-pos=9-4=5 但1111内容是4 所以是size-pos-1
m.insert(make_pair(key, value));
}
pos = interval.find(":");
if (pos != -1)
{
key = interval.substr(0, pos);
value = interval.substr(pos + 1, interval.size() - pos -1 );
m.insert(make_pair(key, value));
}
pos = stuId.find(":");
if (pos != -1)
{
key = stuId.substr(0, pos);
value = stuId.substr(pos + 1, stuId.size() - pos -1 );
m.insert(make_pair(key, value));
}
pos = stuName.find(":");
if (pos != -1)
{
key = stuName.substr(0, pos);
value = stuName.substr(pos + 1, stuName.size() - pos -1);
m.insert(make_pair(key, value));
}
pos = roomId.find(":");
if (pos != -1)
{
key = roomId.substr(0, pos);
value = roomId.substr(pos + 1, roomId.size() - pos -1 );
m.insert(make_pair(key, value));
}
pos = status.find(":");
if (pos != -1)
{
key = status.substr(0, pos);
value = status.substr(pos + 1, status.size() - pos -1);
m.insert(make_pair(key, value));
}
//将小map容器放到大的map容器中
this->m_orderData.insert(make_pair(this->m_Size, m));
this->m_Size++;
}
//测试代码
//for (map<int, map<string, string>>::iterator it = m_orderData.begin(); it != m_orderData.end();it++)
//{
// cout << "key = " << it->first << " value = " << endl;
// for (map<string, string>::iterator mit = it->second.begin(); mit != it->second.end(); mit++)
// {
// cout << mit->first << " " << mit->second << " ";
// }
// cout << endl;
//}
ifs.close();
}
予約レコードを更新するメンバー関数 updateOrder のコードは次のとおりです。
void OrderFile::updateOrder()
{
if (this->m_Size == 0)
{
return;
}
ofstream ofs(ORDER_FILE, ios::out | ios::trunc);
for (int i = 0; i < m_Size;i++)
{
//["date"]是小map 的key,通过key能找到他的value也就是:后面的类容
ofs << "date:" << this->m_orderData[i]["date"] << " ";
ofs << "interval:" << this->m_orderData[i]["interval"] << " ";
ofs << "stuId:" << this->m_orderData[i]["stuId"] << " ";
ofs << "stuName:" << this->m_orderData[i]["stuName"] << " ";
ofs << "roomId:" << this->m_orderData[i]["roomId"] << " ";
ofs << "status:" << this->m_orderData[i]["status"] << endl;
}
ofs.close();
}
8.3.2 自己予約の表示
まず、いくつかの予約レコードを追加しましょう。プログラムを使用して追加することも、order.txt ファイルを直接変更することもできます。
order.txt ファイルの内容は次のとおりです。 たとえば、3 人の生徒がいて、それぞれが 3 つの予約レコードを生成しました。
Student クラスのメンバー関数にvoid Student::showMyOrder()
、次のコードを追加します。
//查看我的预约
void Student::showMyOrder()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "无预约记录" << endl;
system("pause");
system("cls");
return;
}
for (int i = 0; i < of.m_Size; i++)
{
//atio是char转int 但atio里面要放const char*_string类型
//将string对象,转化为char*对象,而c_str()提供了这样一种方法,它返回const char*类型(可读不可改)的指向字符数组的指针。
/*
如何将string 转 int
1、string利用 .c_str() 转成 const char*
2、利用 atoi( const char *) 转 int
*/
if (atoi(of.m_orderData[i]["stuId"].c_str()) == this->m_Id) //找到自身预约
{
cout << "预约日期: 周" << of.m_orderData[i]["date"];
cout << " 时段:" << (of.m_orderData[i]["interval"] == "1" ? "上午" : "下午");
cout << " 机房:" << of.m_orderData[i]["roomId"];
string status = " 状态: "; // 0 取消的预约 1 审核中 2 已预约 -1 预约失败
if (of.m_orderData[i]["status"] == "1")
{
status += "审核中";
}
else if (of.m_orderData[i]["status"] == "2")
{
status += "预约成功";
}
else if (of.m_orderData[i]["status"] == "-1")
{
status += "审核未通过,预约失败";
}
else
{
status += "预约已取消";
}
cout << status << endl;
}
}
system("pause");
system("cls");
}
テストの効果は次の図に示すとおりです。
8.3.3 すべての予定を表示
Student クラスのメンバー関数にvoid Student::showAllOrder()
、次のコードを追加します。
//查看所有预约
void Student::showAllOrder()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "无预约记录" << endl;
system("pause");
system("cls");
return;
}
for (int i = 0; i < of.m_Size; i++)
{
cout << i + 1 << "、 ";
cout << "预约日期: 周" << of.m_orderData[i]["date"];
cout << " 时段:" << (of.m_orderData[i]["interval"] == "1" ? "上午" : "下午");
cout << " 学号:" << of.m_orderData[i]["stuId"];
cout << " 姓名:" << of.m_orderData[i]["stuName"];
cout << " 机房:" << of.m_orderData[i]["roomId"];
string status = " 状态: "; // 0 取消的预约 1 审核中 2 已预约 -1 预约失败
if (of.m_orderData[i]["status"] == "1")
{
status += "审核中";
}
else if (of.m_orderData[i]["status"] == "2")
{
status += "预约成功";
}
else if (of.m_orderData[i]["status"] == "-1")
{
status += "审核未通过,预约失败";
}
else
{
status += "预约已取消";
}
cout << status << endl;
}
system("pause");
system("cls");
}
テストの効果は次の図に示すとおりです。
8.4 予約のキャンセル
Student クラスのメンバー関数にvoid Student::cancelOrder()
、次のコードを追加します。
//取消预约
void Student::cancelOrder()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "无预约记录" << endl;
system("pause");
system("cls");
return;
}
cout << "审核中或预约成功的记录可以取消,请输入取消的记录" << endl;
vector<int>v; //存放在最大容器中的下标编号
int index = 1;
for (int i = 0; i < of.m_Size; i++)
{
//先判断自身学号
if (atoi(of.m_orderData[i]["stuId"].c_str()) == this->m_Id)
{
//再筛选状态 审核中或预约成功
if (of.m_orderData[i]["status"] == "1" || of.m_orderData[i]["status"] == "2")
{
v.push_back(i);
cout << index ++ << "、 ";
cout << "预约日期: 周" << of.m_orderData[i]["date"];
cout << " 时段:" << (of.m_orderData[i]["interval"] == "1" ? "上午" : "下午");
cout << " 机房:" << of.m_orderData[i]["roomId"];
string status = " 状态: "; // 0 取消的预约 1 审核中 2 已预约 -1 预约失败
if (of.m_orderData[i]["status"] == "1")
{
status += "审核中";
}
else if (of.m_orderData[i]["status"] == "2")
{
status += "预约成功";
}
cout << status << endl;
}
}
}
cout << "请输入取消的记录,0代表返回" << endl;
int select = 0;
while (true)
{
cin >> select;
if (select >= 0 && select <= v.size())
{
if (select == 0)
{
break;
}
else
{
// cout << "记录所在位置: " << v[select - 1] << endl;
of.m_orderData[v[select - 1]]["status"] = "0";
of.updateOrder();
cout << "已取消预约" << endl;
break;
}
}
cout << "输入有误,请重新输入" << endl;
}
system("pause");
system("cls");
}
テストキャンセルの予約:
個人的な予定の記録を再度表示します。
すべての予定を表示
order.txt 予約ファイルを表示する
この時点で、すべての学生モジュールの機能が実装されました。
9. 教師モジュール
9.1 教師のログインとログアウト
9.1.1 コンストラクター
- Teacher クラスのコンストラクターで、教師情報を初期化します。コードは次のとおりです。
//有参构造 (职工编号,姓名,密码)
Teacher::Teacher(int empId, string name, string pwd)
{
//初始化属性
this->m_EmpId = empId;
this->m_Name = name;
this->m_Pwd = pwd;
}
9.1.2 教師サブメニュー
- コンピュータ室予約 system.cpp で、ユーザーが教師としてログインするときに、教師メニュー インターフェイスを追加します
- さまざまなブランチを提供する
- すべての予定を表示
- 予約の確認
- ログアウト
- ログアウト機能の実装
次のようにグローバル関数void TeacherMenu(Person * &manager)
コードを追加します。
//教师菜单
void TeacherMenu(Identity * &teacher)
{
while (true)
{
//教师菜单
teacher->operMenu();
Teacher* tea = (Teacher*)teacher;
int select = 0;
cin >> select;
if (select == 1)
{
//查看所有预约
tea->showAllOrder();
}
else if (select == 2)
{
//审核预约
tea->validOrder();
}
else
{
delete teacher;
cout << "注销成功" << endl;
system("pause");
system("cls");
return;
}
}
}
9.1.3 メニュー機能の実装
- メンバー関数を実装するコードは
void Teacher::operMenu()
次のとおりです。
//教师菜单界面
void Teacher::operMenu()
{
cout << "欢迎教师:" << this->m_Name << "登录!" << endl;
cout << "\t\t ----------------------------------\n";
cout << "\t\t| |\n";
cout << "\t\t| 1.查看所有预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 2.审核预约 |\n";
cout << "\t\t| |\n";
cout << "\t\t| 0.注销登录 |\n";
cout << "\t\t| |\n";
cout << "\t\t ----------------------------------\n";
cout << "请选择您的操作: " << endl;
}
9.1.4 インターフェースのドッキング
- 教師がログインに成功すると、教師のサブメニュー インターフェイスが呼び出されます。
- 教師のログイン ブランチにコードを追加します。
//进入教师子菜单
TeacherMenu(person);
追加された効果は図のとおりです。
ドッキングをテストします。結果は以下のようになります。
ログイン検証に合格しました:
教師用サブメニュー:
ログアウト:
9.2 すべての予定を表示する
9.2.1 すべての予約機能の実装
この機能は学生向けの予約全表示機能と同様の機能で、すべての予約記録を表示するために使用されます。
Teacher.cpp にメンバー関数を実装するvoid Teacher::showAllOrder()
void Teacher::showAllOrder()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "无预约记录" << endl;
system("pause");
system("cls");
return;
}
for (int i = 0; i < of.m_Size; i++)
{
cout << i + 1 << "、 ";
cout << "预约日期: 周" << of.m_orderData[i]["date"];
cout << " 时段:" << (of.m_orderData[i]["interval"] == "1" ? "上午" : "下午");
cout << " 学号:" << of.m_orderData[i]["stuId"];
cout << " 姓名:" << of.m_orderData[i]["stuName"];
cout << " 机房:" << of.m_orderData[i]["roomId"];
string status = " 状态: "; // 0 取消的预约 1 审核中 2 已预约 -1 预约失败
if (of.m_orderData[i]["status"] == "1")
{
status += "审核中";
}
else if (of.m_orderData[i]["status"] == "2")
{
status += "预约成功";
}
else if (of.m_orderData[i]["status"] == "-1")
{
status += "审核未通过,预约失败";
}
else
{
status += "预约已取消";
}
cout << status << endl;
}
system("pause");
system("cls");
}
9.2.2 テスト機能
テスト教師として「すべての予定を表示」機能を実行する
テストの効果は次の図に示すとおりです。
9.3 監査の任命
9.3.1 監査機能の実装
機能説明: 教師は生徒の予約を確認し、実際の状況に基づいて予約を確認します
Teacher.cpp にメンバー関数を実装するvoid Teacher::validOrder()
コードは以下のように表示されます。
//审核预约
void Teacher::validOrder()
{
OrderFile of;
if (of.m_Size == 0)
{
cout << "无预约记录" << endl;
system("pause");
system("cls");
return;
}
cout << "待审核的预约记录如下:" << endl;
vector<int>v;
int index = 0;
for (int i = 0; i < of.m_Size; i++)
{
if (of.m_orderData[i]["status"] == "1")
{
v.push_back(i);
cout << ++index << "、 ";
cout << "预约日期: 周" << of.m_orderData[i]["date"];
cout << " 时段:" << (of.m_orderData[i]["interval"] == "1" ? "上午" : "下午");
cout << " 机房:" << of.m_orderData[i]["roomId"];
string status = " 状态: "; // 0取消的预约 1 审核中 2 已预约 -1 预约失败
if (of.m_orderData[i]["status"] == "1")
{
status += "审核中";
}
cout << status << endl;
}
}
cout << "请输入审核的预约记录,0代表返回" << endl;
int select = 0;
int ret = 0;
while (true)
{
cin >> select;
if (select >= 0 && select <= v.size())
{
if (select == 0)
{
break;
}
else
{
cout << "请输入审核结果" << endl;
cout << "1、通过" << endl;
cout << "2、不通过" << endl;
cin >> ret;
if (ret == 1)
{
of.m_orderData[v[select - 1]]["status"] = "2";
}
else
{
of.m_orderData[v[select - 1]]["status"] = "-1";
}
of.updateOrder();
cout << "审核完毕!" << endl;
break;
}
}
cout << "输入有误,请重新输入" << endl;
}
system("pause");
system("cls");
}
9.3.2 テストレビューの予約
テスト - 承認されました
レビュー状況
テスト監査が失敗しました
審査に合格しなかった場合:
学生ステータスでレコードを表示します。
予約の確認が成功しました!
これでこの案件は完了です!