c++面向对象练习——简单图书管理系统

前段时间在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,还请大佬们多多指教

  • 12
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值