前段时间在b站自学了侯捷老师的c++面向对象高级编程,收获颇多。然后自不量力在Github上找了个项目练练手,但步子迈的太大,扯着*了,bug太多,只能放弃。在GitHub上找源码做了几个简单的小项目后,刚好java老师布置一个图书管理系统的作业,就结合c++面向对象做了一个简单图书管理系统。
一.程序要求
为图书阅览室开发一个图书借阅系统,实现图书的管理。图书借阅系统具备以下主要功能。
功能
借出排行榜
新增图书
查看图书
删除图书
借出图书
归还图书
显示图书
二.设计思路
1.Date类处理日期问题
Date.h
#ifndef DATE_H
#define DATE_H
#include <iostream>
#include <string>
using namespace std;
class Date
{
public:
Date(int year=0,int month=0,int day=0);//构造函数
string ShowDate();//输出日期
int getYear() const { return year; }//外部访问接口,获取年
int getMonth() const { return month; }//外部访问接口,获取月
int getDay() const { return day; }//外部访问接口,获取天
protected:
private:
int year;
int month;
int day;
};
#endif // DATE_H
2.Book类实现图书信息封装
Book.h
#ifndef BOOK_H
#define BOOK_H
#include <iostream>
#include <string>
#include "Date.h"
using namespace std;
class Book
{
public:
Book( string bookname,Date data,bool bookislead,int times );//构造函数
void ShowInfo();//显示全部图书信息
void Show_LoanTime();//提供接口,输出图书借出时间
void inTurnout();//图书出库
void outTurnin();//图书入库
void addTimes();//借出次数加一
string getName() const { return BookName; }//外部访问接口,获取图书名称
Date &getDate() { return Data; }//外部访问接口,获取图书借出日期
bool getStatue() const { return BookIsLend; }//外部访问接口,获取图书状态
int getTimes() const { return Times; }//外部访问接口,获取图书借出次数
//virtual ~Book();
protected:
private:
string BookName;//书名
Date Data;//借出日期
bool BookIsLend;//图书是否在库
int Times; //借出次数
};
#endif // BOOK_H
3.MangerBook类实现管理员控制
MangerBook.h
#ifndef MANGERBOOK_H
#define MANGERBOOK_H
#include "Book.h"
#include <vector>
#include <iostream>
#include <cstring>
#include <io.h>
#include <direct.h>
#define EXIT 0
#define LOANRANKING 1
#define ADDBOOK 2
#define SEARCHBOOK 3
#define SELECTBOOK 4
#define LOANBOOK 5
#define RETURNBOOK 6
#define SHOWBOOK 7
#define OTHERS 8
//#define FILENAME "D:/编程/c++图书馆系统/图书信息.txt"
using namespace std;
class MangerBook
{
public:
MangerBook();//构造函数
virtual ~MangerBook();//析构函数
void ShowMenu();//菜单
void Exit_Sys();//退出
void Init_Book();//初始化
void LoanRanking();//借出次数排行榜
void AddBook();//增加图书
void SearchBook();//查找图书
void SelectBook();//删除图书
void LoanBook();//借出图书
int IndexBook(string name);//索引图书在容器中位置
int CntDay( const Date &date1,const Date &date2 );//计算两个日期之间相差多少天
bool LegalDate( const Date &date );//判断日期是否合法
void ReturnkBook();//归还图书
void ShowBook();//显示书库
vector<Book*> *Book_Array;//容器
protected:
private:
};
#endif // MANGERBOOK_H
三.实现功能
Date.cpp
#include "Date.h"
Date::Date(int year,int month,int day)
{
this->year = year;
this->month = month;
this->day = day;
}
string Date::ShowDate()
{
return to_string(this->year) + "-" + to_string(this->month) + "-" + to_string(this->day);
}
Book.cpp
#include "Book.h"
Book::Book( string bookname,Date data,bool bookislead,int times)
{
this->BookName = bookname;
this->Data = data;
this->BookIsLend = bookislead;
this->Times = times;
}
void Book::ShowInfo()
{
cout<<"<<"<<this->BookName<<">>"<<endl;
if(!this->BookIsLend){
cout<<"状态:"<<"在库"<<endl;
}
else{
cout<<"状态:"<<"借出"<<endl;//借出图书输出借出时间
cout<<"借出时间:"<<this->Data.ShowDate()<<endl;
}
cout<<"借出次数:"<<this->Times<<endl;
cout<<endl;
}
void Book::Show_LoanTime()
{
cout<<"借出时间:"<<this->Data.ShowDate()<<endl;
}
void Book::inTurnout()//在借出操作中使用_pstu1替换后,不需要再使用这个函数
{
if(this->BookIsLend==false){
this->BookIsLend = true;
}
}
void Book::outTurnin()
{
if(this->BookIsLend==true){
this->BookIsLend = false;
}
}
void Book::addTimes()
{
this->Times +=1 ;
}
MangerBook.cpp
#include "MangerBook.h"
#include "Book.h"
#include <fstream>
#include <string>
#include <algorithm>
#include <cmath>
MangerBook::MangerBook()//构造函数
{
this->Book_Array = new vector<Book*>;
this->Init_Book();//初始化
}
void MangerBook::Init_Book()
{
/*ifstream fi;
fi.open("D:/编程/c++图书馆系统/图书信息.txt",ios::in);
string _name;
int _year,_month,_day;
int _isleadbook;
int _times;
while(fi>>_name&&fi>>_year&&fi>>_month && fi>>_day&&fi>>_isleadbook&&fi>>_times)
{
Date _data(_year,_month,_day);
Book *_pstu = NULL;
if(_isleadbook==0)
_pstu = new Book(_name,_data,true,_times);
else
_pstu = new Book(_name,_data,false,_times);
this->Book_Array->push_back(_pstu);
}*/
//初始六本书,本来想用文件输入,但是输出乱码,最后也没有解决
//因为怕麻烦,所以在库书和出库书都设置了日期
Book *_pstu1 = NULL;
Date _data1(2023,10,4);
_pstu1 = new Book("数据结构",_data1,false,117);
this->Book_Array->push_back(_pstu1);
Book *_pstu2 = NULL;
Date _data2(2021,10,17);
_pstu2 = new Book("红楼梦",_data2,true,11);
this->Book_Array->push_back(_pstu2);
Book *_pstu3 = NULL;
Date _data3(2023,7,16);
_pstu3 = new Book("计算机网络",_data3,false,98);
this->Book_Array->push_back(_pstu3);
Book *_pstu4 = NULL;
Date _data4(2023,10,4);
_pstu4 = new Book("离散数学",_data1,true,11);
this->Book_Array->push_back(_pstu4);
Book *_pstu5 = NULL;
Date _data5(2023,2,16);
_pstu5 = new Book("操作系统",_data5,false,110);
this->Book_Array->push_back(_pstu5);
Book *_pstu6 = NULL;
Date _data6(2022,10,1);
_pstu6 = new Book("高等数学",_data6,false,111);
this->Book_Array->push_back(_pstu6);
}
void MangerBook::ShowMenu()
{
cout <<"-----------------------------------------------------------"<< endl;
cout <<"-------------------某某大学图书管理系统---------------------"<< endl;
cout <<"----------------------0、退出系统--------------------------"<< endl;
cout <<"---------------------1、借出排行榜-------------------------"<< endl;
cout <<"---------------------2、新增图书---------------------------"<< endl;
cout <<"---------------------3、查看图书---------------------------"<< endl;
cout <<"---------------------4、删除图书---------------------------"<< endl;
cout <<"---------------------5、借出图书---------------------------"<< endl;
cout <<"---------------------6、归还图书---------------------------"<< endl;
cout <<"---------------------7、显示书库---------------------------"<< endl;
cout <<"-----------------------------------------------------------"<< endl;
cout << endl;
}
void MangerBook::Exit_Sys()//退出系统函数
{
cout<<"谢谢使用"<<endl;
exit(-1);
}
bool cmp(Book *book1,Book *book2)//设置排列顺序从大到小
{
return book1->getTimes()>book2->getTimes();
}
void MangerBook::LoanRanking()//借出排行,使用STL,从大到小排列
{
sort(Book_Array->begin(),Book_Array->end(),cmp);
for(int i=0;i<(int)Book_Array->size();i++){
this->Book_Array->at(i)->ShowInfo();
}
system("pause");
system("cls");
}
void MangerBook::ShowBook()//显示在库图书信息
{
for(int i=0;i<(int)Book_Array->size();i++){
this->Book_Array->at(i)->ShowInfo();
}
system("pause");
system("cls");
}
void MangerBook::AddBook()//添加书籍
{
int i=1;//记录添加
while(true)
{
char flag;
string _name;
cout<<"请输入添加第"<<i<<"本书的名字"<< endl;
cin>>_name;
Book *_pstu = NULL;
Date _data(0,0,0);
_pstu = new Book(_name,_data,false,0);//新入库图书默认借出次数为零
this->Book_Array->push_back(_pstu);
i++;
cout <<"是否继续录入信息?"<< endl;
cout <<"Y/y继续录入,N/n结束录入"<< endl;
while(true){ //非法检测
cin >> flag;
if(flag == 'Y' || flag == 'y' || flag == 'N' ||flag == 'n')
{
break;
}
else{
cout <<"输入的指令非法!请重新输入!"<< endl;
}
}
if(flag == 'Y' || flag == 'y'){
continue;
}
else{
break;
}
}
cout << "成功录入了"<<i-1<<"本书信息!"<< endl;
system("pause");
system("cls");
}
void MangerBook::SearchBook()
{
cout<<"请输入待查询书籍名称"<<endl;
string searchname;
cin>>searchname;
int index;
index = IndexBook(searchname);//寻找在数组中位置
if(index!=-1){
this->Book_Array->at(index)->ShowInfo();
}
system("pause");
system("cls");
}
int MangerBook::IndexBook( string name )//索引函数
{
int ret = -1;
for(int i=0;i<(int)Book_Array->size();i++){
if(this->Book_Array->at(i)->getName() == name ){
ret = i;
break;
}
}
return ret;
}
void MangerBook::SelectBook()
{
cout<<"请输入待删除书籍名称"<<endl;
string searchname;
cin>>searchname;
int index;
index = IndexBook(searchname);
if(index!=-1){
if(this->Book_Array->at(index)->getStatue()==false){//书籍不在库则无法删除
this->Book_Array->erase(this->Book_Array->begin()+index);
cout<<"删除成功!"<<endl;
}
else{
cout<<"书籍不在库!,删除失败!"<<endl;
}
}
else{
cout<<"书籍信息不存在!,删除失败!"<<endl;
}
system("pause");
system("cls");
}
void MangerBook::LoanBook()//借出
{
cout<<"请输入书籍名称"<<endl;
string searchname;
cin>>searchname;
int c_year,c_month,c_day;
int index;
index = IndexBook(searchname);
if(index!=-1){
if(this->Book_Array->at(index)->getStatue()==false){//书籍不在库则无法借出
cout<<"请输入借出日期(年 月 日)" << endl;
cin>>c_year >> c_month >> c_day;
Date c_data(c_year, c_month, c_day);
// 检查还书日期的合法性
if (!LegalDate(c_data)) {
cout << "日期非法,请重新输入!" << endl;
// 添加循环以重复要求有效日期
while (true) {
cout<<"请输入借出日期(年 月 日)" << endl;
cin >> c_year >> c_month >> c_day;
c_data = Date(c_year,c_month,c_day);
if (LegalDate(c_data)) {
break;
} else {
cout << "日期非法,请重新输入!" << endl;
}
}
}
Book *_pstu1 = NULL;
Date _data1(c_year,c_month,c_day);
_pstu1 = new Book(searchname,_data1,true,this->Book_Array->at(index)->getTimes()+1);
int insertIndex = index; // 要插入的位置(可以根据需求修改)
if (insertIndex >= 0 && insertIndex < (int)this->Book_Array->size()) {
delete this->Book_Array->at(insertIndex); // 删除原来的对象,避免内存泄漏
this->Book_Array->at(insertIndex) = _pstu1; // 插入新的 Book 对象
}
else {
cout << "插入位置无效!" << endl;
}
cout<<"借出成功,请妥善保管"<<endl;
}
else{
cout<<"书籍不在库!,借出失败!"<<endl;
}
}
else{
cout<<"书籍信息不存在!,借出失败!"<<endl;
}
system("pause");
system("cls");
}
bool isLeapyear(int year)//判断是否是闰年
{
if( (year%4==0&&year%100!=0)||(year%400==0) )
return true;
return false;
}
bool MangerBook::LegalDate( const Date &date) //检测日期合法性
{
int y = date.getYear();
int m = date.getMonth();
int d = date.getDay();
bool ret=true;
if (m > 12 || m<1)
ret=false;
else if ( ( (m == 1) || (m==3) || (m==5) || (m==7) || (m==8) || (m==10) || (m==12) ) && d > 31 )
ret=false;
else if ( ( (m == 4) || (m==6) || (m==9) || (m==11) ) && d > 30)
ret=false;
if (isLeapyear(y) && m == 2 && d > 29)
ret=false;
else if (!isLeapyear(y) && m == 2 && d > 28)
ret=false;
return ret;
}
int diffDay(int year1,int year2,int month2,int day2)//计算相差多少年转化为天,即总天数差
{
int ans=0;
if(year1==year2)
return 0;
else if(year1>year2)
return -1e6;
int cntyear = abs(year2-year1);
for(int i=0;i<cntyear;i++){
ans += 365;
}
for(int i=min(year1,year2);i<=max(year1,year2);i++){
if(isLeapyear(i)){
ans++;
}
}
if(isLeapyear(year2) && ( (month2<2)||(month2==2&&day2<29)))
ans--;
return ans;
}
int Daytoend(int y, int m, int d) //计算到年底的天数
{
int tm = 0, tEY=0;
int month[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
if (isLeapyear(y))
month[1] = 29;
for (m -= 1; m <= 11; m++)
tm += month[m];
tEY = tm - d;
return tEY;
}
int MangerBook::CntDay( const Date &date1,const Date &date2)//计算相差多少天
{
int cntday1=diffDay(date1.getYear(),date2.getYear(),date2.getMonth(),date2.getDay());
int cnt_day_end1=Daytoend(date1.getYear(),date1.getMonth(),date1.getDay());
int cnt_day_end2=Daytoend(date2.getYear(),date2.getMonth(),date2.getDay());
int CalculateDateDifference=cntday1+cnt_day_end1-cnt_day_end2;
//用总天数差加上两个日期到当年年底天数之差即为结果
return CalculateDateDifference;
}
void MangerBook::ReturnkBook()//归还书籍
{
cout << "请输入归还书籍名称" << endl;
string searchname;
cin >> searchname;
int r_year;
int r_month;
int r_day;
int index;
index = IndexBook(searchname);
if (index!=-1) {
if (this->Book_Array->at(index)->getStatue() == true) {
cout<<"请输入归还日期(年 月 日)" << endl;
cin>>r_year>>r_month>>r_day;
Date r_data(r_year,r_month,r_day);
// 检查还书日期的合法性
if (!LegalDate(r_data)) {
cout<<"日期非法,请重新输入!"<<endl;
// 添加循环以重复要求有效日期
while (true) {
cout<<"请输入归还日期(年 月 日)" << endl;
cin>>r_year>>r_month>>r_day;
r_data = Date(r_year,r_month,r_day);
if (LegalDate(r_data)) {
break;
} else {
cout << "日期非法,请重新输入!" << endl;
}
}
}
// 计算租借天数
int chargeDay = CntDay(this->Book_Array->at(index)->getDate(), r_data);
while (chargeDay < 0) {
cout<<"日期非法,请重新输入!" << endl;
cout<<"请输入归还日期(年 月 日)" << endl;
cin>>r_year>>r_month>>r_day;
r_data = Date(r_year, r_month, r_day);
chargeDay = CntDay(this->Book_Array->at(index)->getDate(), r_data);
}
//
this->Book_Array->at(index)->outTurnin();
double charge = chargeDay*0.1;
this->Book_Array->at(index)->Show_LoanTime();
cout<<"借出"<<chargeDay<<"天,日租1角"<<"共需支付"<<charge<<"元"<<endl;
cout<<"归还成功,谢谢使用!"<<endl;
} else {
cout << "已归还,请勿重复归还!" << endl;
}
} else {
cout << "书籍信息不存在!,归还失败!" << endl;
}
system("pause");
system("cls");
}
MangerBook::~MangerBook()//析构函数
{
//dtor
if(this->Book_Array){
this->Book_Array->clear();
delete[] this->Book_Array;
this->Book_Array = NULL;//删除后,让对象指针指向空
}
}
main.cpp
#include <iostream>
#include "MangerBook.h"
using namespace std;
int main()
{
MangerBook gm;// 实例化管理员
int select;//用户选择
while(true)
{
gm.ShowMenu();
cout<<"请选择要执行的操作"<<endl;
while(true)
{
cin>>select;
if(!cin){
cout<<"ERROR!"<<endl;
cin.clear();
select = 1024;
cin.get();
}
if(select>=EXIT||select<=OTHERS){
break;
}
else{
cout<<"指令非法,请重新输入!"<<endl;
system("system");
gm.ShowMenu();
cout<<"请选择要执行的操作"<<endl;
}
}
switch(select)
{
case EXIT: gm.Exit_Sys(); break;
case LOANRANKING: gm.LoanRanking(); break;
case ADDBOOK: gm.AddBook(); break;
case SEARCHBOOK:gm.SearchBook(); break;
case SELECTBOOK:gm.SelectBook(); break;
case LOANBOOK:gm.LoanBook(); break;
case RETURNBOOK:gm.ReturnkBook(); break;
case SHOWBOOK:gm.ShowBook(); break;
default:system("cls"); break;
}
}
return 0;
}
四.部分功能演示
在多重classes设计中,我只使用了组合一种,在传值和引用选择上也有一些地方不合理,程序还可以添加一些功能,比如这个系统中只考虑了一本书(该书在系统中数量上只有一本)的情况,可以在Book类中添加相关变量模拟多本书情况,还可以使用继承将书籍进行分类等等......
控制台设计是Github上学生管理系统项目提供的思路,日期算法也是在CSDN上现学的,可能有些小bug,还请大佬们多多指教