第二十五篇 -- 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,但是现实中的数据量是很大的,用文本来存储学生信息等是很不友好的,所以还得用数据库的方式。此外,这图书也得不一样,借走了就没有,但是如果是真正的图书馆的话,每种类型的书不可能都只有一本,所以如果想添砖加瓦的话,也可以加上书的数量,判断有无剩余,是否可借等。现在,相信整个结构也是非常清晰的,想要添加修改也只需要到相应的地方,并不需要做大的结构变动。
第二十五篇 -- C++宝典中的图书管理系统的更多相关文章
- Egret入门学习日记 --- 第十五篇(书中 6.1~6.9节 内容)
第十五篇(书中 6.1~6.9节 内容) 好的,昨天完成了第五章. 今天来看第六章. 总结重点: 1.如何对组件进行分组? 跟着做: 重点1:如何对组件进行分组? 首先,选中你想要组合的组件. 然后点 ...
- 第二十五篇:在SOUI中做事件分发处理
不同的SOUI控件可以产生不同的事件.SOUI系统中提供了两种事件处理方式:事件订阅 + 事件处理映射表(参见第八篇:SOUI中控件事件的响应) 事件订阅由于直接将事件及事件处理函数连接,不存在事件分 ...
- Python之路(第二十五篇) 面向对象初级:反射、内置方法
[TOC] 一.反射 反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力(自省).这一概念的提出很快引发了计算机科学领域关于应用反射性的研究.它 ...
- flask第二十五篇——控制语句
有兴趣的请加船长公众号:自动化测试实战 先和大家强调一个发邮件的问题 # coding: utf-8 import smtplib from email.mime.text import MIMETe ...
- 第二十五篇:使用 sigaction 函数实现可靠信号
前言 在前文中,讲述了一个可靠信号的示例.它分成几个步骤组成( 请参考前文 ).在 Linux 系统编程中,有个方法可以将这些步骤给集成起来,让我们使用起来更加的方便. 那就是调用 sigaction ...
- SpringBoot非官方教程 | 第二十五篇:2小时学会springboot
转载请标明出处: http://blog.csdn.net/forezp/article/details/61472783 本文出自方志朋的博客 一.什么是spring boot Takes an o ...
- 第二十五篇 jQuery 学习7 获取并设置 CSS 类
jQuery 学习7 获取并设置 CSS 类 jQuery动态控制页面,那么什么是动态呢?我们就说一下静态,静态几乎又纯html+css完成,就是刷新页面之后,不会再出现什么变动,一个实打实的静态 ...
- 第二十八篇:SOUI中自定义控件开发过程
在SOUI中已经提供了大部分常用的控件,但是内置控件不可能满足用户的所有要求,因此一个真实的应用少不得还要做一些自定义控件. 学习一个新东西,最简单的办法就是依葫芦画瓢.事实上在SOUI系统中内置控件 ...
- 第二十五篇 hashlib模块(* *)
用于加密相关的操作,Python 3.x里代替了md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法. 加密复杂程度: SHA1 ...
随机推荐
- FlinkSQL写入Kafka/ES/MySQL示例-JAVA
一.背景说明 Flink的API做了4层的封装,上两层TableAPI.SQL语法相对简单便于编写,面对小需求可以快速上手解决,本文参考官网及部分线上教程编写source端.sink端代码,分别读取s ...
- 【题解】Luogu P1011 车站
题目描述 火车从始发站(称为第1站)开出,在始发站上车的人数为a,然后到达第2站,在第2站有人上.下车,但上.下车的人数相同,因此在第2站开出时(即在到达第3站之前)车上的人数保持为a人.从第3站起( ...
- 【codeforces841A】Generous Kefa
原题 A. Generous Kefatime limit per test:2 secondsmemory limit per test:256 megabytes input:standard i ...
- TypeScript 在开发应用中的实践总结
背景 以前 hybrid app 的移动端开发模式下,H5 和客户端通信的 js sdk 代码使用 js 编写,sdk 方法的说明使用文档输出.对于开发的使用来说,在 IDE 中不能得到友好的参数类型 ...
- react 工程目录简介
创建一个 todolist 项目,下图是其工程目录. node_modules文件夹 里面存放的是我们所建项目放所依赖的第三方的包 public文件夹 favicon.ico 图标文件,网页标题左上角 ...
- javascript之一切都是对象
在学习的过程中,我们常常能听到这样一句话:一切皆是对象.那么这句话该如何理解呢?首先,我们要明确对象的概念.要明白除了基本数据类型都是对象. typeof操作符是大家经常使用的,我们常用它来检测给定变 ...
- [源码解析] 深度学习分布式训练框架 horovod (10) --- run on spark
[源码解析] 深度学习分布式训练框架 horovod (10) --- run on spark 目录 [源码解析] 深度学习分布式训练框架 horovod (10) --- run on spark ...
- @Autowired报错原因分析和4种解决方案!
上图的报错信息相信大部分程序员都遇到过,奇怪的是虽然代码报错,但丝毫不影响程序的正常执行,也就是虽然编译器 IDEA 报错,但程序却能正常的执行,那这其中的原因又是为何? 报错原因分析 报错的原因 ...
- MySQL之where条件数据筛选
语法: -- select * from 表名 where 条件; 测试数据: -- 建表语句 create table `student` ( `sid` int(11) primary key a ...
- Devexpress-WPF初体验
最近使用wpf devexpress做一个wpf小项目,中间遇到了一些问题,这里记录下,同时也跟大家分享分享 1.devexpress安装 devexpress提供了很多控件,特别是各种形式的数据列表 ...