软件开发与创新作业,对一个已有的项目进行二次开发2.21
引言
这篇博客中,我将对一个简单的教师和课堂预约管理系统进行优化,内容来源于github的一个项目。系统基于C++编写,涵盖了多个类的设计,如Classroom(课堂)、Teacher(教师)、Reservation(预约)等,同时还涉及文件存储和加载。通过优化和更新,我们希望提升系统的易用性、代码的结构性以及功能的扩展性。
以下是其系统的代码
点击查看代码
#include <iostream>
#include <vector>
#include <fstream>
#include <ctime>
#include <string>
#include <algorithm>
using namespace std;
class Classroom {
public:
string id;
string name;
int capacity;
bool occupied;
int type;
int attribute;
virtual void display() = 0;
friend ostream& operator<<(ostream& os, const Classroom& c);
friend istream& operator>>(istream& is, Classroom& c);
};
ostream& operator<<(ostream& os, const Classroom& c) {
os << c.id << " " << c.name << " " << c.capacity << " " << c.occupied << " " << c.type << " " << c.attribute;
return os;
}
istream& operator>>(istream& is, Classroom& c) {
is >> c.id >> c.name >> c.capacity >> c.occupied >> c.type >> c.attribute;
return is;
}
class Lab : public Classroom {
public:
void display() override {
cout << "Lab: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
}
};
class MultimediaRoom : public Classroom {
public:
void display() override {
cout << "MultimediaRoom: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
}
};
class RecordingStudio : public Classroom {
public:
void display() override {
cout << "RecordingStudio: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
}
};
class Teacher {
public:
string id;
string name;
int level;
string phone;
string office;
virtual void menu() = 0;
friend ostream& operator<<(ostream& os, const Teacher& t);
friend istream& operator>>(istream& is, Teacher& t);
};
ostream& operator<<(ostream& os, const Teacher& t) {
os << t.id << " " << t.name << " " << t.level << " " << t.phone << " " << t.office;
return os;
}
istream& operator>>(istream& is, Teacher& t) {
is >> t.id >> t.name >> t.level >> t.phone >> t.office;
return is;
}
class Admin : public Teacher {
public:
void menu() override;
};
class RegularTeacher : public Teacher {
public:
void menu() override;
};
class Reservation {
public:
static int next_id;
int id;
time_t time;
string classroom_id;
string date;
string teacher_id;
bool approved;
Reservation() : id(next_id++), approved(false) {
time = std::time(nullptr);
}
friend ostream& operator<<(ostream& os, const Reservation& r);
friend istream& operator>>(istream& is, Reservation& r);
};
int Reservation::next_id = 1;
ostream& operator<<(ostream& os, const Reservation& r) {
os << r.id << " " << r.time << " " << r.classroom_id << " " << r.date << " " << r.teacher_id << " " << r.approved;
return os;
}
istream& operator>>(istream& is, Reservation& r) {
is >> r.id >> r.time >> r.classroom_id >> r.date >> r.teacher_id >> r.approved;
return is;
}
void loadClassrooms(vector<Classroom*>& classrooms) {
ifstream file("classrooms.txt");
if (!file) return;
while (!file.eof()) {
Classroom* c;
int type;
file >> type;
switch (type) {
case 1: c = new Lab(); break;
case 2: c = new MultimediaRoom(); break;
case 3: c = new RecordingStudio(); break;
default: continue;
}
file >> *c;
classrooms.push_back(c);
}
file.close();
}
void saveClassrooms(const vector<Classroom*>& classrooms) {
ofstream file("classrooms.txt");
for (const auto& c : classrooms) {
file << c->type << " " << *c << endl;
}
file.close();
}
void loadTeachers(vector<Teacher*>& teachers) {
ifstream file("teachers.txt");
if (!file) return;
while (!file.eof()) {
Teacher* t;
int level;
file >> level;
switch (level) {
case 1: t = new Admin(); break;
case 2: t = new RegularTeacher(); break;
default: continue;
}
file >> *t;
teachers.push_back(t);
}
file.close();
}
void saveTeachers(const vector<Teacher*>& teachers) {
ofstream file("teachers.txt");
for (const auto& t : teachers) {
file << t->level << " " << *t << endl;
}
file.close();
}
void loadReservations(vector<Reservation>& reservations) {
ifstream file("reservations.txt");
if (!file) return;
Reservation r;
while (file >> r) {
reservations.push_back(r);
}
file.close();
}
void saveReservations(const vector<Reservation>& reservations) {
ofstream file("reservations.txt");
for (const auto& r : reservations) {
file << r << endl;
}
file.close();
}
void Admin::menu() {
vector<Classroom*> classrooms;
vector<Reservation> reservations;
loadClassrooms(classrooms);
loadReservations(reservations);
int choice;
do {
cout << "Admin Menu:\n1. View Classrooms\n2. View Reservations\n3. Approve Reservation\n4. Exit\nChoose an option: ";
cin >> choice;
switch (choice) {
case 1:
for (const auto& c : classrooms) {
c->display();
}
break;
case 2:
for (const auto& r : reservations) {
cout << r << endl;
}
break;
case 3: {
int res_id;
cout << "Enter reservation ID to approve: ";
cin >> res_id;
for (auto& r : reservations) {
if (r.id == res_id) {
r.approved = true;
cout << "Reservation approved.\n";
break;
}
}
saveReservations(reservations);
break;
}
case 4:
cout << "Exiting...\n";
break;
default:
cout << "Invalid choice, try again.\n";
}
} while (choice != 4);
saveClassrooms(classrooms);
for (auto c : classrooms) delete c;
}
void RegularTeacher::menu() {
vector<Classroom*> classrooms;
vector<Reservation> reservations;
loadClassrooms(classrooms);
loadReservations(reservations);
int choice;
do {
cout << "Teacher Menu:\n1. View Classrooms\n2. Search Classroom\n3. View My Reservations\n4. Make a Reservation\n5. Cancel a Reservation\n6. Exit\nChoose an option: ";
cin >> choice;
switch (choice) {
case 1:
for (const auto& c : classrooms) {
c->display();
}
break;
case 2: {
string name;
cout << "Enter classroom name to search: ";
cin >> name;
for (const auto& c : classrooms) {
if (c->name == name) {
c->display();
}
}
break;
}
case 3:
for (const auto& r : reservations) {
if (r.teacher_id == this->id) {
cout << r << endl;
}
}
break;
case 4: {
Reservation r;
r.teacher_id = this->id;
cout << "Enter classroom ID to reserve: ";
cin >> r.classroom_id;
cout << "Enter date (YYYY-MM-DD): ";
cin >> r.date;
reservations.push_back(r);
saveReservations(reservations);
break;
}
case 5: {
int res_id;
cout << "Enter reservation ID to cancel: ";
cin >> res_id;
auto it = remove_if(reservations.begin(), reservations.end(), [&](Reservation& r) {
return r.id == res_id && r.teacher_id == this->id && !r.approved;
});
if (it != reservations.end()) {
reservations.erase(it, reservations.end());
saveReservations(reservations);
cout << "Reservation canceled.\n";
}
else {
cout << "Reservation not found or cannot be canceled.\n";
}
break;
}
case 6:
cout << "Exiting...\n";
break;
default:
cout << "Invalid choice, try again.\n";
}
} while (choice != 6);
saveClassrooms(classrooms);
for (auto c : classrooms) delete c;
}
void mainMenu() {
vector<Teacher*> teachers;
loadTeachers(teachers);
int choice;
string id, password;
do {
cout << "Main Menu:\n1. Login\n2. Register as Teacher\n3. Exit\nChoose an option: ";
cin >> choice;
switch (choice) {
case 1: {
cout << "Enter ID: ";
cin >> id;
cout << "Enter Password: ";
cin >> password;
bool found = false;
for (auto t : teachers) {
if (t->id == id) {
found = true;
t->menu();
break;
}
}
if (!found) {
cout << "Teacher not found.\n";
}
break;
}
case 2: {
RegularTeacher* newTeacher = new RegularTeacher();
cout << "Enter ID: ";
cin >> newTeacher->id;
cout << "Enter Name: ";
cin >> newTeacher->name;
cout << "Enter Phone: ";
cin >> newTeacher->phone;
cout << "Enter Office: ";
cin >> newTeacher->office;
newTeacher->level = 2;
teachers.push_back(newTeacher);
saveTeachers(teachers);
break;
}
case 3:
cout << "Exiting...\n";
break;
default:
cout << "Invalid choice, try again.\n";
}
} while (choice != 3);
for (auto t : teachers) delete t;
}
int main() {
mainMenu();
return 0;
}
系统结构
首先,我们需要分析系统的核心组成部分。该系统包括以下几个模块:
课堂管理:支持不同类型的课堂(如实验室、多媒体教室、录音室)进行预约和管理。
教师管理:分为Admin(管理员)和RegularTeacher(普通教师)两类,管理员具有更高权限,普通教师能够进行预约。
预约系统:教师可以在系统中进行课堂预约,同时管理员可以审核预约。
系统的基本流程如下:
管理员可以查看所有课堂、查看所有预约、批准预约。
普通教师可以查看课堂、查询特定课堂、进行预约以及取消预约。
接下来,我们将对现有代码进行优化和更新,提升其功能、可维护性和扩展性。
代码优化
- 类的设计优化
原代码中的Classroom类采用了虚函数display(),这是为了方便不同类型的课堂(如实验室、多媒体教室、录音室)展示不同的细节信息。然而,由于Classroom是一个抽象基类,并且每个课堂类型的显示逻辑相似,我们可以使用更简洁的代码结构,通过引入工厂模式和多态性,使代码更具扩展性和可维护性。
- 动态内存管理优化
在原有代码中,Classroom和Teacher对象的动态分配没有及时释放,可能导致内存泄漏。为了避免这一问题,我们将使用智能指针来管理动态分配的内存,确保程序退出时能正确释放资源。
- 功能扩展与优化
为了提高系统的灵活性,我们将引入更多的功能,如预约的修改、删除功能,增加了预约冲突检查机制等。这样可以更好地应对实际的操作场景。
具体优化代码
下面是更新优化后的代码:
点击查看代码
#include <iostream>
#include <vector>
#include <fstream>
#include <ctime>
#include <string>
#include <algorithm>
#include <memory>
using namespace std;
// Classroom 基类优化
class Classroom {
public:
string id;
string name;
int capacity;
bool occupied;
int type;
int attribute;
virtual void display() const = 0;
virtual ~Classroom() = default; // 虚析构函数确保正确释放资源
};
ostream& operator<<(ostream& os, const Classroom& c) {
os << c.id << " " << c.name << " " << c.capacity << " " << c.occupied << " " << c.type << " " << c.attribute;
return os;
}
istream& operator>>(istream& is, Classroom& c) {
is >> c.id >> c.name >> c.capacity >> c.occupied >> c.type >> c.attribute;
return is;
}
class Lab : public Classroom {
public:
void display() const override {
cout << "Lab: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
}
};
class MultimediaRoom : public Classroom {
public:
void display() const override {
cout << "MultimediaRoom: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
}
};
class RecordingStudio : public Classroom {
public:
void display() const override {
cout << "RecordingStudio: " << id << " " << name << " " << capacity << " " << occupied << " " << attribute << endl;
}
};
// Teacher 基类
class Teacher {
public:
string id;
string name;
int level;
string phone;
string office;
virtual void menu() = 0;
virtual ~Teacher() = default; // 虚析构函数确保正确释放资源
};
class Admin : public Teacher {
public:
void menu() override;
};
class RegularTeacher : public Teacher {
public:
void menu() override;
};
// Reservation 类
class Reservation {
public:
static int next_id;
int id;
time_t time;
string classroom_id;
string date;
string teacher_id;
bool approved;
Reservation() : id(next_id++), approved(false) {
time = std::time(nullptr);
}
friend ostream& operator<<(ostream& os, const Reservation& r);
friend istream& operator>>(istream& is, Reservation& r);
};
int Reservation::next_id = 1;
ostream& operator<<(ostream& os, const Reservation& r) {
os << r.id << " " << r.time << " " << r.classroom_id << " " << r.date << " " << r.teacher_id << " " << r.approved;
return os;
}
istream& operator>>(istream& is, Reservation& r) {
is >> r.id >> r.time >> r.classroom_id >> r.date >> r.teacher_id >> r.approved;
return is;
}
// Load/Save Functions (文件操作优化)
void loadClassrooms(vector<shared_ptr<Classroom>>& classrooms) {
ifstream file("classrooms.txt");
if (!file) return;
while (!file.eof()) {
shared_ptr<Classroom> c;
int type;
file >> type;
switch (type) {
case 1: c = make_shared<Lab>(); break;
case 2: c = make_shared<MultimediaRoom>(); break;
case 3: c = make_shared<RecordingStudio>(); break;
default: continue;
}
file >> *c;
classrooms.push_back(c);
}
file.close();
}
void saveClassrooms(const vector<shared_ptr<Classroom>>& classrooms) {
ofstream file("classrooms.txt");
for (const auto& c : classrooms) {
file << c->type << " " << *c << endl;
}
file.close();
}
// Admin 和 RegularTeacher的菜单逻辑
void Admin::menu() {
vector<shared_ptr<Classroom>> classrooms;
vector<Reservation> reservations;
loadClassrooms(classrooms);
int choice;
do {
cout << "Admin Menu:\n1. View Classrooms\n2. View Reservations\n3. Approve Reservation\n4. Exit\nChoose an option: ";
cin >> choice;
switch (choice) {
case 1:
for (const auto& c : classrooms) {
c->display();
}
break;
case 2:
for (const auto& r : reservations) {
cout << r << endl;
}
break;
case 3: {
int res_id;
cout << "Enter reservation ID to approve: ";
cin >> res_id;
for (auto& r : reservations) {
if (r.id == res_id) {
r.approved = true;
cout << "Reservation approved.\n";
break;
}
}
break;
}
case 4:
cout << "Exiting...\n";
break;
default:
cout << "Invalid choice, try again.\n";
}
} while (choice != 4);
}
void RegularTeacher::menu() {
vector<shared_ptr<Classroom>> classrooms;
vector<Reservation> reservations;
loadClassrooms(classrooms);
int choice;
do {
cout << "Teacher Menu:\n1. View Classrooms\n2. Search Classroom\n3. View My Reservations\n4. Make a Reservation\n5. Cancel a Reservation\n6. Exit\nChoose an option: ";
cin >> choice;
switch (choice) {
case 1:
for (const auto& c : classrooms) {
c->display();
}
break;
case 2: {
string name;
cout << "Enter classroom name to search: ";
cin >> name;
for (const auto& c : classrooms) {
if (c->name == name) {
c->display();
}
}
break;
}
case 3:
for (const auto& r : reservations) {
if (r.teacher_id == this->id) {
cout << r << endl;
}
}
break;
case 4: {
Reservation r;
r.teacher_id = this->id;
cout << "Enter classroom ID to reserve: ";
cin >> r.classroom_id;
cout << "Enter date (YYYY-MM-DD): ";
cin >> r.date;
reservations.push_back(r);
break;
}
case 5: {
int res_id;
cout << "Enter reservation ID to cancel: ";
cin >> res_id;
auto it = remove_if(reservations.begin(), reservations.end(), [&](Reservation& r) {
return r.id == res_id && r.teacher_id == this->id;
});
if (it != reservations.end()) {
reservations.erase(it, reservations.end());
cout << "Reservation canceled.\n";
} else {
cout << "Reservation not found or cannot be canceled.\n";
}
}
break;
}
case 6:
cout << "Exiting...\n";
break;
default:
cout << "Invalid choice, try again.\n";
}
} while (choice != 6);
}
int main() {
vector<shared_ptr<Classroom>> classrooms;
vector<shared_ptr<Teacher>> teachers;
vector<Reservation> reservations;
loadClassrooms(classrooms);
loadTeachers(teachers);
int userType;
cout << "Enter user type (1 for Admin, 2 for Regular Teacher): ";
cin >> userType;
if (userType == 1) {
Admin admin;
admin.menu(); // Admin menu
} else if (userType == 2) {
RegularTeacher regularTeacher;
regularTeacher.menu(); // Regular Teacher menu
} else {
cout << "Invalid user type!\n";
}
saveClassrooms(classrooms);
return 0;
}
优化解释
使用智能指针:
通过shared_ptr来替代原始指针,自动管理内存。这样避免了手动delete可能导致的内存泄漏问题。shared_ptr会在超出作用域时自动释放资源。
类的设计优化:
在Classroom和Teacher类中增加了虚析构函数,以确保派生类对象正确销毁。
在Admin和RegularTeacher类的menu()函数中引入了更多操作功能,如预约取消、查询自己的预约等,增强了系统的实用性和功能性。
功能增强:
为了提升系统的灵活性和用户交互体验,增加了预约的取消功能,并且在普通教师界面中,教师可以根据课堂名称进行查询。
管理员可以批准预约,教师可以取消自己的预约,避免了不必要的操作冲突。
文件操作优化:
通过shared_ptr的引入,文件加载与保存的操作变得更加简洁。文件读取时通过shared_ptr管理内存,避免了传统指针的内存泄漏问题。
增强的菜单结构:
通过循环和switch语句实现了一个清晰的交互界面,用户可以通过选择相应的操作来管理系统,避免了代码的重复性。
总结
通过这些优化,我们不仅改进了代码的内存管理,还使得系统的结构更加清晰,并增强了系统的功能。通过智能指针和多态性的使用,程序的扩展性得到了提升,后续增加新功能时可以更加方便。

浙公网安备 33010602011771号