第二十五篇 -- C++宝典中的图书管理系统
此篇文章是基于C++宝典写的图书管理系统,本人对其中的部分做了相应修改,并且以现有格式替代原有格式,使程序更加清晰明了。此程序运行在VS2017上。
系统设计
图书管理系统分为四个模块:图书管理模块、读者管理模块、借书模块和还书模块。
总体设计
图书管理:对图书基本信息进行维护,主要包括新增图书、更改图书基本信息、删除图书、查找图书等功能模块。
读者管理:对读者的基本信息进行维护,主要包括增加读者、删除读者信息、查找特定读者等功能模块。
借书:进行图书借阅操作,该部分是整个图书管理系统中最主要的部分,需要对图书文件和读者文件同时进行读写。
还书:进行图书归还操作,该功能模块也需要对图书文件和读者文件同时进行读写。
系统结构图
效果图:
输入3,进入图书管理
输入5,显示图书
代码:
Book.h
#pragma once #include <iostream> #include <iomanip> using namespace std; class Book //图书类,实现对图书的描述,图书的编号、书名、借出、还入等 { private: int tag; //删除标记,1:已删,0:未删 int no; //图书编号 char name[20]; //书名 int onshelf; //是否可借,1:可借,2:不可借 public: Book() {} //构造函数 char *getname(); int getno(); int gettag(); void setname(char na[]); void delbook(); void addbook(int n, char *na); int borrowbook(); void retbook(); void disp(); };
Book.cpp
#include "pch.h" #include "Book.h" char* Book:: getname() { return name; //获取姓名 } int Book:: getno() { return no; //获取图书编号 } int Book:: gettag() { return tag; //获取删除标记 } void Book:: setname(char na[]) { strcpy_s(name, 20, na); //设置书名 } void Book:: delbook() { tag = 1; //删除图书 } void Book:: addbook(int n, char *na) { //增加图书 tag = 0; no = n; strcpy_s(name, 20, na); onshelf = 1; } int Book:: borrowbook() { //借书操作 if (onshelf == 1) { //当前图书可借 onshelf = 0; return 1; } return 0; } void Book:: retbook() { //还书操作 onshelf = 1; } void Book:: disp() { cout << setw(6) << no << setw(18) << name << setw(10) << (onshelf == 1 ? "可借" : "不可借") << endl; //cout << setw(6) << no << setw(18) << name << setw(10) << (onshelf == 1 ? "Yes" : "No") << endl; }
BDatabase.h
#pragma once #include "Book.h" #include <iostream> #include <fstream> using namespace std; #define Maxb 100 class BDatabase //图书库类,实现对图书的维护、查找、删除等 { private: int top; //图书记录指针 Book book[Maxb]; //图书记录 public: BDatabase(); ~BDatabase(); void clear(); int addbook(int n, char *na); //增加图书 Book *query(int bookid); //查找图书 void bookdata(); //图书库维护 void disp(); };
BDatabase.cpp
#include "pch.h" #include "BDatabase.h" BDatabase:: BDatabase() { //构造函数,将book.txt读到book[]中 Book b; //定义图书对象 top = -1; //初始化图书记录指针 fstream file; //ifstream file; file.open("book.txt", ios::in); //以读取方式打开数据文件book.txt //file.open("book.txt"); //以读取方式打开数据文件book.txt while (1) { //读取数据文件book.txt中的图书记录 file.read((char *)&b, sizeof(b)); if (!file) break; top++; book[top] = b; } file.close(); } BDatabase::~BDatabase() { //析构函数,将book[]写到book.txt文件中 fstream file("book.txt", ios::out); //以写入方式打开数据文件book.txt //ofstream file("book.txt"); //以写入方式打开数据文件book.txt for (int i = 0; i <= top; i++) { if (book[i].gettag() == 0) { file.write((char*)&book[i], sizeof(book[i])); //file << book[i].gettag(); //file.write("", 3); //file << book[i].getno(); //file.write("", 3); //file.write(book[i].getname(), 20); //file.write("", 4); } } file.close(); //关闭文件 } void BDatabase:: clear() { //全删 top = -1; } void BDatabase::disp() { for (int i = 0; i <= top; i++) { if (book[i].gettag() == 0) { book[i].disp(); //显示该图书记录 } } } Book* BDatabase::query(int bookid) { //查找图书 for (int i = 0; i <= top; i++) { if (book[i].getno() == bookid && book[i].gettag() == 0) { return &book[i]; //返回查找结果 } } return NULL; } int BDatabase::addbook(int n, char *na) { //增加图书 Book *p = query(n); //查找是否有重复图书编号 if (NULL == p) { //该图书编号无重复 top++; //记录指针加1 book[top].addbook(n, na); //调用图书类的增加图书成员函数 return 1; } return 0; //该图书编号重复 } void BDatabase::bookdata() { //维护图书成员函数 char choice = '1'; //定义变量 char bname[40]; int bookid; Book *b; //创建图书对象 while (choice != '0') { //当输入不等于0时 cout << "\n\n\n************** 图书维护 **************" << endl << endl; cout << "\t\t1 新 增\n\t\t2 更 改\n\t\t3 删 除\n\t\t4 查 找\n\t\t5 显 示\n\t\t6 全 删\n\t\t0 退 出" << endl; cout << "请选择操作:"; cin >> choice; //输入选项 switch (choice) { case '1': //选择新增图书功能 cout << "输入图书编号:" << endl; cin >> bookid; cout << "输入图书书名:" << endl; cin >> bname; addbook(bookid,bname); //调用addbook函数 break; case '2': //选择更改图书功能 cout << "输入图书编号:" << endl; cin >> bookid; b = query(bookid); //调用query函数 if (b == NULL) { //未找到该图书 cout << " 该图书不存在 " << endl; break; } cout << "输入新的书名:" << endl; cin >> bname; b->setname(bname); //重新设置图书名称 break; case '3': //选择删除图书功能 cout << "请输入要删除的图书编号:" << endl; cin >> bookid; b = query(bookid); //调用query函数 if (b == NULL) { cout << " 该图书不存在" << endl; break; } b->delbook(); //删除图书 break; case '4': //选择查找图书功能 cout << "请输入要查找的图书编号:" << endl; cin >> bookid; b = query(bookid); //调用query函数 if (b == NULL) { cout << " 该图书不存在" << endl; break; } b->disp(); //显示找到的图书信息 break; case '5': //选择显示所有图书功能 disp(); break; case '6': //选择全部删除图书功能 clear(); break; default: cout << "输入错误,请重新输入:"; //错误的输入 break; } } }
Reader.h
#pragma once #include <string.h> #include <iostream> #include <iomanip> using namespace std; #define Maxbor 5 class Reader //读者类,实现对读者信息的描述 { public: Reader(); ~Reader(); private: int tag; //删除标记,1:已删,0:未删 int no; //读者编号 char name[10]; //读者姓名 int borbook[Maxbor]; //所借图书 public: char *getname(); //获取姓名 int gettag(); //获取删除标记 int getno(); //获取读者编号 void setname(char na[]); //设置姓名 void delreader(); //设置删除标记,1:已删,0:未删 void addreader(int n, char *na); //增加读者 void borrowbook(int bookid); //借书操作 int retbook(int bookid); //还书操作 void disp(); //读出读者信息 };
Reader.cpp
#include "pch.h" #include "Reader.h" Reader::Reader() { } Reader::~Reader() { } char* Reader::getname() { return name; } int Reader::gettag() { return tag; } int Reader::getno() { return no; } void Reader::setname(char na[]) { strcpy_s(name, 10, na); } void Reader::delreader() { tag = 1; } void Reader::addreader(int n, char *na) { tag = 0; no = n; strcpy_s(name, 10, na); //设置读者姓名 for (int i = 0; i < Maxbor; i++) borbook[i] = 0; //设置所借书籍为空 } void Reader::borrowbook(int bookid) { for (int i = 0; i < Maxbor; i++) { //小于最大借书数目 if (borbook[i] == 0) { borbook[i] = bookid; //设置所借书籍的图书编号 return; } } } int Reader::retbook(int bookid) { for (int i = 0; i < Maxbor; i++) { if (borbook[i] == bookid) { //设置读者所借书籍字段中对应的图书编号为空 borbook[i] = 0; return 1; } } return 0; } void Reader::disp() { cout << setw(5) << no << setw(10) << name << "借书编号:["; for (int i = 0; i < Maxbor; i++) { if (borbook[i] != 0) { cout << borbook[i] << "|"; } } cout << "]" << endl; }
RDatabase.h
#pragma once #include "Reader.h" #include <iostream> #include <fstream> using namespace std; #define Maxr 100 class RDatabase //读者库类,实现建立读者的个人资料 { public: RDatabase(); //构造函数,将reader.txt读到read[]中 ~RDatabase(); //析构函数,将read[]写到reader.txt文件中 public: void clear(); //删除所有读者信息 int addreader(int n, char *na); //添加读者时先查找是否存在 Reader *query(int readerid); //按编号查找 void disp(); //输出所有读者信息 void readerdata(); //读者库维护 private: int top; //读者记录指针 Reader read[Maxr]; //读者记录 };
RDatabase.cpp
#include "pch.h" #include "RDatabase.h" RDatabase::RDatabase() { Reader s; top = -1; fstream file("reader.txt", ios::in); //打开一个输入文件 while (1) { file.read((char*)&s, sizeof(s)); if (!file) break; top++; read[top] = s; } file.close(); //关闭reader.txt } RDatabase::~RDatabase() { fstream file("reader.txt", ios::out); for (int i = 0; i <= top; i++) { if (read[i].gettag() == 0) { file.write((char*)&read[i], sizeof(read[i])); } } file.close(); } void RDatabase::clear() { top = -1; } void RDatabase::disp() { for (int i = 0; i <= top; i++) { read[i].disp(); } } Reader* RDatabase::query(int readerid) { for (int i = 0; i <= top; i++) { if (read[i].getno() == readerid && read[i].gettag() == 0) { return &read[i]; } } return NULL; } int RDatabase::addreader(int n, char *na) { //添加读者时先查找是否存在 Reader *p = query(n); //首先查找读者 if (p == NULL) { //未找到该读者编号 top++; read[top].addreader(n, na); return 1; } return 0; } void RDatabase::readerdata() { char choice = '1'; //定义变量 char rname[20]; int readerid; Reader *r; //创建对象 while (choice != '0') { cout << "\n\n\n************** 读者维护 **************" << endl << endl; cout << "\t\t1 新 增\n\t\t2 更 改\n\t\t3 删 除\n\t\t4 查 找\n\t\t5 显 示\n\t\t6 全 删\n\t\t0 退 出" << endl; cout << "请选择操作:"; cin >> choice; //输入选项 switch (choice) { case '1': //选择新增读者功能 cout << "输入读者编号:" << endl; cin >> readerid; cout << "输入读者姓名:" << endl; cin >> rname; addreader(readerid, rname); //调用addreader函数 break; case '2': //选择更改读者功能 cout << "输入读者编号:" << endl; cin >> readerid; r = query(readerid); //调用query函数 if (r == NULL) { //未找到该图书 cout << " 该读者不存在 " << endl; break; } cout << "输入新的姓名:" << endl; cin >> rname; r->setname(rname); //重新设置读者姓名 break; case '3': //选择删除读者功能 cout << "请输入要删除的读者编号:" << endl; cin >> readerid; r = query(readerid); //调用query函数 if (r == NULL) { cout << " 该读者不存在" << endl; break; } r->delreader(); //删除读者 break; case '4': //选择查找读者功能 cout << "请输入要查找的读者编号:" << endl; cin >> readerid; r = query(readerid); //调用query函数 if (r == NULL) { cout << " 该读者不存在" << endl; break; } r->disp(); //显示找到的读者信息 break; case '5': //选择显示所有读者功能 disp(); break; case '6': //选择全部删除读者功能 clear(); break; default: cout << "输入错误,请重新输入:"; //错误的输入 break; } } }
Main.cpp
// 图书管理系统.cpp : This file contains the 'main' function. Program execution begins and ends there. // #include "pch.h" #include <iostream> using namespace std; #include "BDatabase.h" #include "RDatabase.h" int borrow(); int ret(); int main() //main函数的实现,程序的主界面的引导 { char choice = '1'; int bookid, readerid; RDatabase ReaderDB; Reader *r; BDatabase BookDB; Book *b; while (choice != '0') { cout << endl << endl << "******************** 图 书 管 理 系 统 ********************\n\n\n"; cout << "\t\t\t1 借 书\n\n\t\t\t2 还 书\n\n\t\t\t3 图 书 管 理\n\n\t\t\t4 读 者 管 理\n\n\t\t\t0 离 开" << endl; cout << endl << endl << "******************************************************************\n\n\n"; cout << "请选择需要进行的操作序号:"; cin >> choice; //接收用户输入的选项 switch (choice) { case '1': //选择借书模块 borrow(); break; case '2': //选择还书模块 ret(); break; case '3': //选择图书管理模块 BookDB.bookdata(); break; case '4': //选择读者管理模块 ReaderDB.readerdata(); break; default: cout << "输入错误,请重新输入:"; break; } } } int borrow() { //借书模块 int bookid, readerid; //定义变量 RDatabase ReaderDB; //创建对象 Reader *r; //定义对象指针 BDatabase BookDB; Book *b; cout << " 借书\n请输入读者编号:" << endl; cin >> readerid; cout << "请输入图书编号:" << endl; cin >> bookid; r = ReaderDB.query(readerid); //按编号查找读者 if (NULL == r) { //读者编号不存在 cout << " 不存在该读者,不能借书" << endl; exit(0); //正常结束程序 } b = BookDB.query(bookid); //按编号查找图书 if (b == NULL) { //图书编号不存在 cout << " 不存在该图书,不能借书" << endl; exit(0); } if (b->borrowbook() == 0) { //是否借出 cout << " 该图书已借出,不能借书" << endl; exit(0); } r->borrowbook(b->getno()); //结束 cout << "借书成功!" << endl; return 0; } int ret() { //还书模块 int bookid, readerid; RDatabase ReaderDB; Reader *r; BDatabase BookDB; //定义对象指针 Book *b; cout << "还书\n请输入读者编号:"; cin >> readerid; cout << "请输入图书编号:"; cin >> bookid; r = ReaderDB.query(readerid); //调用读者库的query函数 if (r == NULL) { //未找到读者 cout << " 不存在该读者,不能还书" << endl; exit(0); //正常退出 } b = BookDB.query(bookid); //调用图书库的query函数 if (b == NULL) { //未找到读者 cout << " 不存在该图书,不能还书" << endl; exit(0); //正常退出 } b->retbook(); //图书类成员函数还书 r->retbook(b->getno()); //读者类成员函数还书 cout << "还书成功!" << endl; }
如此,一个简单的图书管理系统就完成了,做的过程中,可能会有些许疑惑,比如,为什么两个库文本打开为什么乱码,那是因为是以二进制的方式写入文本的,自然会乱码,不过读取时也是以二进制的方式,所以没有什么问题,那么为什么要用二进制的方式呢,因为用文本方式存储信息不但浪费空间,而且不便于检索,具体可以看看这篇文章:http://c.biancheng.net/view/302.html
另外,这个管理确实简单,针对数量不多的存储。这里面规定的最大数量也就是100,但是现实中的数据量是很大的,用文本来存储学生信息等是很不友好的,所以还得用数据库的方式。此外,这图书也得不一样,借走了就没有,但是如果是真正的图书馆的话,每种类型的书不可能都只有一本,所以如果想添砖加瓦的话,也可以加上书的数量,判断有无剩余,是否可借等。现在,相信整个结构也是非常清晰的,想要添加修改也只需要到相应的地方,并不需要做大的结构变动。