圖書管理系統(C++)


圖書管理系統(C++)

注意事項:

在代碼測試之前必須先建立文件並導入內容以供測試使用,系統沒有提示內容,用起來可能感到十分晦澀難以理解(可直接參考源代碼,源代碼還是非常淺顯易懂的),這里僅供學習參考,不追求功能完善與實用性,如有問題或錯誤敬請諒解,歡迎積極指出。

源代碼:

//遇到的幾個問題:

//先寫最重要的問題:可以考慮使用繼承,因為很多功能都是類似的,使用繼承我覺得至少可以減少三分之一的代碼量(待解決)(另外注釋掉的調試的代碼沒有去掉,方便自己看的時候注意到該注意的問題)

//最該注意的問題:重載,重載的輸入輸出很嚴格,不能有絲毫差錯,否則文件讀取失敗,程序相當於崩潰(已解決)

//對於虛刪問題(map的刪除與重建問題)其實覺得似乎每刪除一個對象都要進行修改的話,當數據量過大時,反而效率不會太高吧
//所以使用的是使用時進行刪除先虛刪,然后當該次操作完成后保存文件時進行對虛刪的處理,然后在保存與再讀取時相當於進行了實刪(這里只是針對管理端的刪除書籍與刪除用戶操作)(已實現)

//對於模糊搜索的問題,原意應該是出現每個字符最多(最符合搜索內容的一項,但是這似乎要用到對字符串的處理(同學似乎是這樣說的)(待處理,似乎也並不是好處理的)
//我用的是精確一點的查找,例如對書籍信息來說可以直接搜索書籍的書名,或者作者,出版社等信息進行搜索,重名等可以直接顯示
//搜索完記下要搜索書籍的書號再精確進行對該書的具體查詢

//對於借閱日期來說,其實可以將每個借閱日期轉化為具體整數,然后通過兩個整數之間的差值來進行判斷是否超期,但是比較麻煩,在計算時間時如果使用int則需要對每組時間數據進行循環賦值,效率也並不高
//另外對於日期的處理似乎可以對日期進行加減號重載,然后我們可以得出兩者的日期差來判斷是否超期或何時歸還然后直接顯示的問題(對於超期判斷的重載待處理)(但是我們在借書時如果書籍已經被借完了,我們可以通過借閱記錄以及續借記錄來進行具體推測出最早的書籍應何時歸還)
//已通過重載加減號實現

//其余還有的問題就寫在代碼中了(不摘出來了)(大體的功能可以實現了,還有很多細節待優化)
//這里用的是管理端與用戶端結合到一起的,沒有摘出來分為管理端與用戶端(其實復制粘貼過去應該就能實現兩個代碼),這里添加了登錄情況,可以直接登錄為管理端或客戶端(當然這次代碼里沒有使用管理端(注釋掉了,取消注釋也可以直接用))


//對於書籍查詢的繼承,由於一開始寫的是查詢與修改寫到了一起(管理端),用戶端查詢與借閱寫到了一起,當然這里可以把查詢列出來寫一個大類,然后使用繼承。
//另外對於文件的導入與保存,可以使用繼承,至少在文件的保存上(調用save函數)都是一樣的。(待處理)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<fstream>
using namespace std;

class Data     //起初只是用來表示出版日期,后來發現借閱與歸還日期都可用
{
    int year;
    int month;
    int day;
public:
    Data(){};
    Data(int year1,int month1,int day1):year(year1),month(month1),day(day1){};
    friend ostream&operator<<(ostream&os,const Data&d);
    friend istream&operator>>(istream&is,Data&d);
    bool operator<(const Data &d)const    //日期比較函數
    {return year!=d.year?year<d.year:month!=d.month?month<d.month:day<d.day;}
    int operator-(Data d)  //對日期的操作,可以直接按月份進行兩個月的相減操作,也可以按如下方式進行精確一點的操作(還可以判斷平年閏年進行更精確的操作)
	{
	    if(year<d.year||(year==d.year&&month<d.month)||(year==d.year&&month==d.month&&day<d.day))
            return -1;  //當日期沒有辦法相減(后面的日期大時)
        int m[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};  //按下標(對應月份)補齊,第一個數不計,對於每年的二月按28天計(不考慮平年閏年)
	    int count=0;
	    int a=d.year,b=d.month,c=d.day;
	    while(1)
	    {
            if(this->year==a&&this->month==b&&this->day==c) break;
	        if(c==m[b]){
                c=1;
                if(b==12)
                 {
                     b=1;
                     a++;
                 }
                 else b++;
	        }
	        else c++;
	        count++;
        }
	        return count;
	}
	Data operator+ (int x)
	{
        int m[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};  //按下標(對應月份)補齊,第一個數不計,對於每年的二月按28天計(不考慮平年閏年)
        while(x--)
        {
            if(day==m[month])
            {
                day=1;
                if(month==12)
                {
                    year++;
                    month=1;
                }
                else month++;
            }
            else day++;
        }
        return *this;
	}
};

istream&operator>>(istream&is,Data&d)    //先重載出版日期的輸入輸出
{
    while(1)
    {
        is>>d.year>>d.month>>d.day;
        if(d.year<1900||d.year>2019||d.month<1||d.month>12||d.day<1||d.day>31); //這里可以優化為判斷閏年或平年然后進行判斷
        else break;
    }
    return is;
}
ostream&operator<<(ostream&os,const Data&d)
{
    //os<<"year:"<<d.year<<" "<<"month:"<<d.month<<" "<<"day:"<<d.day;
    //為了輸入輸出相統一,改為下面的輸出形式
    os<<d.year<<" "<<d.month<<" "<<d.day;
    return os;
}

class Book        //書籍信息
{
    string name;
    string writer;
    string number;
    string press;  //出版社
    Data data;  //出版日期
    int zongshu,kejie;
    int guancang;   //后來加的,圖書館會館藏一些書籍(非外借),可以用該量來判斷書籍是否外借
    string s_name,s_writer,s_number,s_press,s_data,s_zongshu,s_kejie,s_guancang;
public:
    Book(){};
    Book(string name1,string writer1,string number1,string press1,Data data1,int zongshu1,int kejie1):name(name1),writer(writer1),number(number1),press(press1),data(data1),zongshu(zongshu1),kejie(kejie1),guancang(zongshu1-kejie1){};
    void bookclear() {name="0"; writer="0"; number="0"; press="0"; zongshu=0; kejie=0; guancang=0;} //虛刪
    string getPress() {return press;}
    Data getdata() {return data;}
    string getName() {return name;}
    string getWriter() {return writer;}
    string getNumber() {return number;}
    int getZongshu() {return zongshu;}
    int getKejie() {return kejie;}
    int getGuancang() {return guancang;}
    void setGuancang(int guancang1) {guancang=guancang1;}
    void setZongshu(int zongshu1) {zongshu=zongshu1;}
    void setKejie(int kejie1) {kejie=kejie1;}
    //類的整體輸入輸出(重載輸入輸出函數),不再構造打印函數了
    friend ostream&operator<<(ostream&os,const Book&b);    //書籍信息會變動(不能用const)(但是像出版信息就沒有必要修改,直接const)
    friend istream&operator>>(istream&is,Book&b);
    bool operator==(const Book &b)const
    {
        return name!=b.name?0:writer!=b.writer?0:number!=b.number?0:1;        //其實只需判斷number(書號唯一)
    }
};

istream&operator>>(istream&is,Book&b)     //重載書籍信息的輸入輸出
{
    is>>b.s_name>>b.name>>b.s_writer>>b.writer>>b.s_number>>b.number>>b.s_press>>b.press>>b.s_data>>b.data>>b.s_zongshu>>b.zongshu>>b.s_kejie>>b.kejie>>b.s_guancang>>b.guancang;
    //b.guancang=b.zongshu-b.kejie;
    return is;
}
ostream&operator<<(ostream&os,const Book&b)
{
    os<<"book.name: "<<b.name<<" "<<"writer: "<<b.writer<<" "<<"book.number: "<<b.number<<" "<<"book.press: "<<b.press<<" "<<"book.publishdata: "<<b.data<<" "<<"zongshu: "<<b.zongshu<<" "<<"kejie: "<<b.kejie<<" "<<"guancang.not.lend: "<<b.guancang<<endl;
    return os;
}

class Reader   //用戶信息
{
    string name;
    string number;
    int jieyue;
    int kejie;
    int xujie_;
    string s_name,s_number,s_yijie,s_kejie,s_jieshuxinxi,s_xujie,s_lend,s_back;
    Book b1;
    Data d1,d2;
    vector<Book>reader;        //已借閱的書籍信息
    vector<Book>::iterator it;
    vector<Data>jieyuedata;
    vector<Data>backdata;  //當然這里可以直接使用map關聯
    vector<Data>::iterator d;
    vector<int>xujie;   //對於每組借閱的書籍信息進行記錄,只存0和1(續借過記為1,反之為0)
    //vector<int>::iterator ii; 對於續借這里直接也是通過下標解決了
public:
    Reader(){};
    Reader(string name1,string number1,int jieyue1):name(name1),number(number1),jieyue(0){};
    void clearReader() {reader.clear();}
    void clear() {name="0"; number="0";}
    string getName() {return name;}
    string getNumber() {return number;}
    int getJieyue() {return jieyue;}
    void setName(string name1) {name=name1;}
    void setNumber(string number1) {number=number1;}
    //這里需要對用戶個人的借書記錄進行增刪操作(借書記錄操作只有增刪兩步)
    //當一次借閱或歸還好幾本的時候,可以通過while(次數i--)進行i次循環調用函數進行操作
    void addjieyue(Book b,Data day) {jieyue++; reader.push_back(b); jieyuedata.push_back(day); Data day_=day+30; backdata.push_back(day_); xujie_=0; xujie.push_back(xujie_);}            //if(jieyue<10)在外部進行判斷
    int backjieyue(Book b)      //if(jieyue>=10)在外部進行判斷
    {
        //jieyue--;
        //首先要在自己借到的書中找到那本書,確保自己有該書后歸還
        int i=0,j=0;
        int ii=0;      //表示輸入的圖書是否借閱過,能否進行歸還(防止輸入錯誤信息刷借閱量)
        for(it=reader.begin();it!=reader.end();it++)
        {
            //找到就還,找不到就無法還
            //{reader.erase(it); i=j; jieyue--; break;} //break一定要加,因為很有可能一個用戶借了兩本一樣的書(代借)(這可能有反規定,如果需要避免這種情況可以在借書時加限制,但是圖書館似乎允許這種代借,只是名義上不准代借而已)
        //當使用迭代器時需要對賦值號等符號進行重載,另外Data數據在此代碼中只是具體到天(如果按天查詢刪除會出現錯誤)(一天借了好幾本書時)
        //試過使用map將書籍與借閱日期進行關聯,但在輸出時由於兩個自定義類的輸出使用迭代器賦值初始值時又會產生以上問題(並不太容易實現,總是產生與STL內部相沖突的問題)
        //試過使用一個類將書籍與借閱日期進行關聯,但是類向量的刪除也會存在以上問題
        //總之,重載符盡量還是少用比較好(因為上面的幾種實驗總是與STL內部相沖突。。。)
            if(*it==b){
            reader.erase(it);
            jieyue--;
            ii=1;
            i=j;
            /*for(int k=i;k<=getJieyue()-1;k++) { jieyuedata[k]=jieyuedata[k++]; xujie[k]=xujie[k++]; }*/ //下標法不易實現,直接查找刪除更便捷
            jieyuedata.erase(jieyuedata.begin()+j);
            backdata.erase(backdata.begin()+j);
            xujie.erase(xujie.begin()+j);
            break;
           }
            j=j+1;
        }
        return ii;
    }
    int xujiejieyue(Book book,Data day)  //int判斷是否續借成功(因為要返回寫入續借記錄,如果續借失敗則沒有記錄,反之則應記錄)
    {
        int ii=0;
        int i=0;
        for(it=reader.begin();it!=reader.end();it++)
        {
            if(*it==book)
            {
                if(xujie[i]==1)
                    cout<<"flase,yixujie"<<endl;
                else
                {
                    jieyuedata[i]=day;  //續借日期當天記為新借閱日期
                    backdata[i]=day+30;
                    xujie[i]++;
                    ii=1;
                }
                break;
            }
            i++;
        }
        return ii;
    }
    int chaoqi(Data d)
    {
        int count=0;
        for(int i=0;i<reader.size();i++)
        {
            if(d-jieyuedata[i]>30)   //d-backdata[i]>0
            {
                cout<<reader[i];
                count++;
            }
        }
        return count;
    }
    friend ostream&operator<<(ostream&os,const Reader&r);
    friend istream&operator>>(istream&is,Reader&r);
};
//對每一位用戶保證輸入輸出相同,這樣我們就可以完全從用戶數據中讀取與操作數據
//中間試圖對用戶輸入信息正確性做判斷(用了幾個while(1)),但是每次操作完數據都是那樣不會變的,因此默認為數據是正確的
istream&operator>>(istream&is,Reader&r)
{
    is>>r.s_name>>r.name>>r.s_number>>r.number>>r.s_yijie>>r.jieyue>>r.s_kejie>>r.kejie;
    r.reader.clear();
    r.jieyuedata.clear();
    r.backdata.clear();
    r.xujie.clear();
    if(r.jieyue!=0)
    {
        is>>r.s_jieshuxinxi;
        for(int i=0;i<r.jieyue;i++)
        {
            //如果在這里定義Book b1;Data d1;然后輸入再導入的話不會成功的,只有定義在類內然后進行操作才可以
            is>>r.b1;
            r.reader.push_back(r.b1);
            is>>r.s_lend;
            is>>r.d1;
            is>>r.s_back;
            is>>r.d2;
            r.jieyuedata.push_back(r.d1);
            r.backdata.push_back(r.d2);
            is>>r.s_xujie;
            is>>r.xujie_;
            r.xujie.push_back(r.xujie_);
        }
    }
    return is;
}

ostream&operator<<(ostream&os,const Reader&r)
{
    os<<"name:"<<" "<<r.name<<" "<<"number:"<<" "<<r.number<<" "<<"yijie:"<<" "<<r.jieyue<<" "<<"kejie:"<<" "<<(10-r.jieyue)<<endl;
    if(r.reader.size()!=0)
    {
        os<<"jieshuxinxi:"<<endl;
        for(int i=0;i<r.jieyue;i++)       //這里嘗試使用迭代器,但是使用迭代器似乎又要重載運算符“=”(賦值號)
            os<<r.reader[i]<<"lend:"<<" "<<r.jieyuedata[i]<<" "<<"back:"<<" "<<r.backdata[i]<<" "<<"xujie:"<<" "<<r.xujie[i]<<endl;
    }
    return os;
}

class Record  //總借閱記錄
{
    //string bookname,writer,booknumber;
    Book book;  //直接用書籍的整體信息去替代部分信息
    string name,number;  //借閱記錄在這里是不可見其他用戶私人借書信息的(用戶端)(當然管理端可通過查找用戶來完全進行查看)
    Data data;     //表示借閱日期歸還日期(還有續借日期)
    string fangshi; //借、還、續借
    //用戶查詢記錄只是簡單地查詢所需書籍當下的記錄(很久之前的記錄,比如借了又換上的記錄沒有必要也沒有權限查詢
    //((管理端是有的)所以針對管理端,要利用multimap對每組記錄進行排序或查詢(通過用戶查找,或通過書籍查找,或者按時間進行時間段查詢等)
    //管理端該查詢還待補充
    string name_,number_;
public:
    Record(){};
    Record(Book book1,string name1,string number1,Data data1,string fangshi1):book(book1),name(name1),number(number1),data(data1),fangshi(fangshi1) {};
    Book getBook() {return book;}
    string getBooknumber() {return book.getNumber();}
    string getName() {return name;}
    string getnumber() {return number;}
    Data getData() {return data;}
    string getFangshi() {return fangshi;}
    //記錄沒必要使用set函數
    //友元重載輸入輸出
    friend ostream&operator<<(ostream&os,const Record&rec);
    friend istream&operator>>(istream&is,Record&rec);
};

istream&operator>>(istream&is,Record&rec)
{
    while(is>>rec.fangshi)
    {
        if(rec.fangshi=="lend:"||rec.fangshi=="back:"||rec.fangshi=="xujie:")
            break;
    }
    //is>>rec.bookname>>rec.writer>>rec.booknumber>>rec.name>>rec.number>>rec.data;
    is>>rec.name_>>rec.name>>rec.number_>>rec.number>>rec.book>>rec.data;
    return is;
}

ostream&operator<<(ostream&os,const Record&rec)
{
    if(rec.fangshi=="lend:")
        os<<"lend:"<<" ";
        else if(rec.fangshi=="back:")
            os<<"back:"<<" ";
            else
                os<<"xujie:"<<" ";
    //os<<"bookname:"<<rec.bookname<<" "<<"writer:"<<rec.writer<<" "<<"booknumber:"<<rec.booknumber<<endl;
    os<<"username:"<<" "<<rec.name<<" "<<"usernumber:"<<" "<<rec.number<<endl;
    os<<rec.book;
    os<<rec.data<<endl;
    return os;
}

class Guanliop
{
    vector<Book>book;
    vector<Reader>user;
    vector<Record>record;
    multimap<string,int>bookname;
    multimap<string,int>writer;
    multimap<string,int>booknumber;
    multimap<string,int>press;
    multimap<Data,int>publishdata;

    multimap<string,int>name;
    multimap<string,int>number;
    //記錄查詢一般是按日期來查
    multimap<Data,int>data;
    /* multimap<string,int>bookname1; multimap<string,int>writer1; multimap<string,int>booknumber1; */
    multimap<string,int>name1;
    multimap<string,int>number1;

    multimap<string,int>::iterator m,m1,m2;
    multimap<Data,int>::iterator d,d1,d2;
public:
    Guanliop(){loadbook(),loaduser(),loadrecord();}
    //~Guanliop() {save();}
    ~Guanliop() {};
    //讀取從三個文件依次讀取(當某個文件讀取失敗時不會影響另外兩個)
    //保存文件直接保存三個即可
    void loadbook();
    void loaduser();
    void loadrecord();
    void save();
    void addBook();
    void search();
    void setBook();   //對書籍的操作,首先要查找該書,其次進行修改或刪除
    void openBook();  //書籍全覽
    void addReader();
    void setReader();
    void openReader(); //用戶全覽
    void openRecord(); //記錄只查不改
};

void Guanliop::loadbook()
{
    Book b;
    ifstream in("2018212591馬俊光的書籍.txt",ios::in);
    if(!in)
    {
        cout<<"Can't load book!"<<endl;
        return;
    }
    book.clear();
    bookname.clear();
    writer.clear();
    booknumber.clear();
    press.clear();
    publishdata.clear();
    while(in>>b)   //與增添書籍信息代碼一致(后來講到的的復用似乎可以使用)
    {
        //讀取與保存時無需考慮重復情況,因為增添時已經進行了操作
        book.push_back(b);
        bookname.insert(make_pair(b.getName(),book.size()-1));
        writer.insert(make_pair(b.getWriter(),book.size()-1));
        booknumber.insert(make_pair(b.getNumber(),book.size()-1));
        press.insert(make_pair(b.getPress(),book.size()-1));
        publishdata.insert(make_pair(b.getdata(),book.size()-1));
    }
    in.close();
};

void Guanliop::loaduser()
{
    Reader u;
    ifstream infile("2018212591馬俊光的用戶.txt",ios::in);
    if(!infile)
    {
        cout<<"Can't load user!"<<endl;
        return;
    }
    user.clear();
    name.clear();
    number.clear();
    while(infile>>u)
    {
        user.push_back(u);
        name.insert(make_pair(u.getName(),user.size()-1));
        number.insert(make_pair(u.getNumber(),user.size()-1));
    }
    infile.close();
}

void Guanliop::loadrecord()
{
    Record r;
    record.clear();
    data.clear();
    /* bookname1.clear(); writer1.clear(); booknumber1.clear(); */
    //管理端待操作
    name1.clear();
    number1.clear();
    ifstream inrec("2018212591馬俊光的記錄.txt",ios::in);
    {
        if(!inrec)
        {
            cout<<"Can't load record!"<<endl;
            return;
        }
    }
    inrec.close();
}

void Guanliop::save()
{

    ofstream outfile("2018212591馬俊光的用戶.txt",ios::out);
    if(!outfile)
    {
        cout<<"Save User false!";
        return;
    }
    for(int i=0;i<user.size();i++)
    {
        if(user[i].getNumber()=="0");
        else outfile<<user[i];
    }
    outfile.close();

    ofstream outbook("2018212591馬俊光的書籍.txt",ios::out);
    if(!outbook)
    {
        cout<<"Save Book false!";
        return;
    }
    for(int i=0;i<book.size();i++)
    {
        if(book[i].getNumber()=="0");
        else outbook<<book[i];
    }
    outbook.close();
    return;
};

void Guanliop::addBook()
{
    Book b;
    cin>>b;
    m=booknumber.find(b.getNumber());      //看之前是否存在該書
    if(m!=booknumber.end())
    {
        int zongshu1=book[m->second].getZongshu()+b.getZongshu();
        int guancang1=book[m->second].getGuancang()+b.getGuancang();
        int kejie1=book[m->second].getKejie()+b.getKejie();
        book[m->second].setZongshu(zongshu1);
        book[m->second].setKejie(kejie1);
        book[m->second].setGuancang(guancang1);
    }
    else
    {
        book.push_back(b);
        bookname.insert(make_pair(b.getName(),book.size()-1));
        writer.insert(make_pair(b.getWriter(),book.size()-1));
        booknumber.insert(make_pair(b.getNumber(),book.size()-1));
        press.insert(make_pair(b.getPress(),book.size()-1));
        publishdata.insert(make_pair(b.getdata(),book.size()-1));
    }
}

void Guanliop::search()
{
    string in;
    cin>>in;
    int i=0;     //標記是否查到
    m=booknumber.find(in);
    if(m!=booknumber.end())
    {
        i=1;
        cout<<"Found"<<endl;
        cout<<book[m->second];
    }
    else
    {
        m=bookname.find(in);
        m1=bookname.lower_bound(in);
        m2=bookname.upper_bound(in);
        for(m=m1;m!=m2;m++)
        {
            i=1;
            cout<<book[m->second];
        }
        m=writer.find(in);
        m1=writer.lower_bound(in);
        m2=writer.upper_bound(in);
        for(m=m1;m!=m2;m++)
        {
            i=1;
            cout<<book[m->second];
        }
        m=press.find(in);
        m1=press.lower_bound(in);
        m2=press.upper_bound(in);
        for(m=m1;m!=m2;m++)
        {
            i=1;
            cout<<book[m->second];
        }
        //出版日期查詢略去,因為一般是不會只記得出版日期的(這里輸入也存在差異,不再對其進行處理)
        //這里又把日期查詢顯示出來:(當輸入publishdata時按出版日期查詢)
        //(在此之前in為publishdata,因此前面查不到也不輸出任何信息)
        if(in=="publishdata")
        {
            Data data_;
            cin>>data_;
            d=publishdata.find(data_);
            d1=publishdata.lower_bound(data_);
            d2=publishdata.upper_bound(data_);
            for(d=d1;d!=d2;d++)
            {
                i=1;
                cout<<book[d->second];
            }
        }
    }
    if(i==0)
    cout<<"Not Found!"<<endl;
}

void Guanliop::setBook()
{
    //由於我們規定的書號是唯一的(每一種書一個書號),我們便可以利用書號對書籍進行查找修改與刪除等操作
    string in;
    cin>>in;
    int i=0;     //標記是否查到
    m=booknumber.find(in);
    if(m!=booknumber.end())
    {
        i=1;
        cout<<book[m->second];
        string caozuo;
        while(cin>>caozuo)
        {
            if(caozuo=="clear"||caozuo=="delete"||caozuo=="return")
                break;
        }
        if(caozuo=="return");
        if(caozuo=="clear")  //清空書籍數據信息
        {
            if(book[m->second].getGuancang()!=(book[m->second].getZongshu()-book[m->second].getKejie()))  //此時有該種類型書目借出,不可清零
            cout<<"lend not back,clear false"<<endl;
            else
            {
                book[m->second].bookclear();       //暫時還沒有刪掉multimap里的數據m=name.find(s);
                //這里使用book[m->second]獲取書籍信息后,可以對每個map使用查找並判斷其關聯值是否為i來進行刪除
                booknumber.erase(m);
            }
        }
        if(caozuo=="delete") //刪除幾本或全部刪除(但是保留書籍信息)或者更改可借與館藏關系(這里只寫到要刪除幾本書)
        {
            /* while(1) //本來是set函數,但是覺得書籍整體信息不會變 { cin>>caozuo; if(caouzo=="bookname") { cin>>caozuo; book[m->second].setName(caozuo); } if(caozuo=="writer") { cin>>caozuo; book[m->second].setWriter(writer); } } */
            int j;
            cin>>j;    //表示刪除幾本
            if(book[m->second].getKejie()>=j)
            {
                int k=book[m->second].getKejie()-j;
                int o=book[m->second].getZongshu()-j;
                book[m->second].setKejie(k);
                book[m->second].setZongshu(o);
            }
            else cout<<"not enough!"<<endl;
        }
    }
    if(i==0)
    cout<<"Not Found!"<<endl;
}

void Guanliop::addReader()
{
    Reader r;
    cin>>r;
    m=number.find(r.getNumber());
    if(m==number.end())
    {
        user.push_back(r);
        name.insert(make_pair(r.getName(),user.size()-1));
        number.insert(make_pair(r.getNumber(),user.size()-1));
    }
    else cout<<"user existed,add false"<<endl;
}

void Guanliop::setReader()
{
    //先查找用戶
    string fangshi;
    cin>>fangshi;
    int i=0;
    m=number.find(fangshi);
    if(m!=number.end())
    {
        i=1;
        string s=user[m->second].getName();
        string ss=user[m->second].getNumber();
        int j=m->second;
        string caozuo;
        cout<<"Found"<<endl;
        cout<<user[m->second];
        while(1)
        {
            cin>>caozuo;
            if(caozuo=="clear"||caozuo=="set"||caozuo=="return")
                break;
        }
        if(caozuo=="return");
        if(caozuo=="set")
        {
            while(1){
            cin>>caozuo;
            if(caozuo=="name")
            {
                cin>>caozuo;
                //user[j].setName(caozuo); //一定不能先改名,否則map查找查的是新名,然后就給刪除了。。。
                //name.insert(make_pair(caozuo,j));
                //cout<<user[j].getName()<<endl;
                m=name.find(user[j].getName());
                //if(m!=name.end()){ //該句其實沒有必要,因為一定存在
                m1=name.lower_bound(user[j].getName());
                m2=name.upper_bound(user[j].getName());
                for(m=m1;m!=m2;m++)
                {
                    if(m->second==j)
                    {
                        name.erase(m);
                        break;  //不加break會導致程序出現問題。。。//其實無所謂了,發現不是這里的問題(不過加上也挺好的,不必接着遍歷了,因為只需要刪除那一個就好)
                    }
                }
                name.insert(make_pair(caozuo,j));
                user[j].setName(caozuo);
                /* for(m=name.begin();m!=name.end();m++) { cout<<m->first<<" "<<m->second<<endl; } */
                //}
            }
            //借閱號碼是唯一,默認不可改(這里不做處理)
            if(caozuo=="end")
                break;
            }
        }
        if(caozuo=="clear")
        {
            user[j].clear();  //這里名字map已刪除
            m=name.find(s);
            m1=name.lower_bound(s);
            m2=name.upper_bound(s);
            for(m=m1;m!=m2;m++)
            if(m->second==j)
            {
                 name.erase(m);
                 break;
            }
            m=number.find(ss);
            m1=number.lower_bound(ss);
            m2=number.upper_bound(ss);
            for(m=m1;m!=m2;m++)
            if(m->second==j)
            {
                 number.erase(m);
                 break;
            }
        }
    }
    else {
    m=name.find(fangshi);
    m1=name.lower_bound(fangshi);
    m2=name.upper_bound(fangshi);
    for(m=m1;m!=m2;m++)
    {
        i=1;
        cout<<user[m->second];
    }
    }
    if(i==0)
        cout<<"Not Found!"<<endl;
}

//以總覽的方式全部顯示書籍
void Guanliop::openBook()
{
    //按書名進行排序查看
    string fangshi;
    while(1)
    {
        cin>>fangshi;
        if(fangshi=="bookname"||fangshi=="writer"||fangshi=="booknumber"||fangshi=="press"||fangshi=="data")
            break;
    }
    if(fangshi=="bookname")
    for(m=bookname.begin();m!=bookname.end();m++)
    {
        cout<<book[m->second]<<endl;
    }
    if(fangshi=="writer")
    for(m=writer.begin();m!=writer.end();m++)
    {
        cout<<book[m->second]<<endl;
    }
    if(fangshi=="booknumber")
    for(m=booknumber.begin();m!=booknumber.end();m++)
    {
        cout<<book[m->second]<<endl;
    }
    if(fangshi=="press")
    for(m=press.begin();m!=press.end();m++)
    {
        cout<<book[m->second]<<endl;
    }
    if(fangshi=="data")
    for(d=publishdata.begin();d!=publishdata.end();d++)
    {
        cout<<book[d->second]<<endl;
    }
}
void Guanliop::openReader()
{
    string fangshi;
    while(1)
    {
        cin>>fangshi;
        if(fangshi=="name"||fangshi=="number")
            break;
    }
    if(fangshi=="name")
    for(m=name.begin();m!=name.end();m++)
        cout<<user[m->second];
    if(fangshi=="number")
    for(m=number.begin();m!=number.end();m++)
        cout<<user[m->second];
}

class Readerop:public Guanliop
{
    //用戶端首先要找到自己,然后能查到所有書籍的相關信息
    vector<Reader>user;
   // vector<Reader>::iterator it;
    vector<Book>book;
    vector<Record>rec;  //要導入的總的記錄
    vector<Record>rec1;  //要查詢的書籍的記錄(處理后的)
    multimap<string,int>bookname;
    multimap<string,int>writer;
    multimap<string,int>booknumber;
    multimap<string,int>press;
    multimap<Data,int>publishdata;
    multimap<string,int>recnumber;  //記錄書號輸出記錄
    //其實也可以直接來定義<Bppk,int>的形式
    multimap<string,int>::iterator m,m1,m2;
    multimap<Data,int>::iterator d1,d2,d3;
    //使用Record應該先重載
    //multimap<Record,int>record;
    //multimap<Record,int>::iterator r;

    //Reader r;
    int i_;
    Data d;
public:
    //Readerop(){}; //這里初始的時候就直接構造文件內容,就不使用空構造了,測試這里時由於直接定義一開始沒有導入文件內容,導致測不出東西
    //Readerop(int i,Data d){this->r=user[i],this->d=d,uload(),bload();}
    Readerop() {bload();}  //每個用戶都應該能對書籍進行全面查詢
    Readerop(int i1,Data d1):i_(i1),d(d1) {uload(),bload(),recload();}
    ~Readerop(){save();};
    Reader getUser() {return user[i_];}
    void uload();
    void bload();
    void recload();
    //void search(int j); //借書包含在搜索一欄中
    void lend(int j);
    void back();
    void xujie(int j);   //續借需要記錄續借日期,然后從該日期開始記錄一個月記為下次還書日期
    void save();
};

void Readerop::uload()
{

    //重復,但是要讀取用戶信息
    Reader u;
    ifstream infile("2018212591馬俊光的用戶.txt",ios::in);
    if(!infile)
    {
        cout<<"Can't load user!"<<endl;
        return;
    }
    //這里不再用map來查找等工作了,不再建立map
    user.clear();
    while(infile>>u)
    {
        user.push_back(u);
    }
    infile.close();
}

void Readerop::bload()
{
        //先導入書籍信息,方便查詢與借閱
        Book b;
        ifstream in("2018212591馬俊光的書籍.txt",ios::in);
        if(!in)
        {
            cout<<"Can't load book!"<<endl;
            return;
        }
        book.clear();
        bookname.clear();
        writer.clear();
        booknumber.clear();
        press.clear();
        publishdata.clear();
        while(in>>b)   //與增添書籍信息代碼一致(后來講到的的復用似乎可以使用)
        {
            //讀取與保存時無需考慮重復情況,因為增添時已經進行了判斷操作
            book.push_back(b);
            bookname.insert(make_pair(b.getName(),book.size()-1));
            writer.insert(make_pair(b.getWriter(),book.size()-1));
            booknumber.insert(make_pair(b.getNumber(),book.size()-1));
            press.insert(make_pair(b.getPress(),book.size()-1));
            publishdata.insert(make_pair(b.getdata(),book.size()-1));
        }
        in.close();
}

void Readerop::recload()
{
    Record rec1;
    ifstream in("2018212591馬俊光的記錄.txt",ios::in);
    if(!in)
    {
        cout<<"Can't load record!"<<endl;
        return;
    }
    rec.clear();
    recnumber.clear();
    //record.clear();
    while(in>>rec1)
    {
        rec.push_back(rec1);
        //record.insert(make_pair(rec1,rec.size()-1));
        recnumber.insert(make_pair(rec1.getBooknumber(),rec.size()-1));
    }
    in.close();
}

void Readerop::save()
{
    ofstream outfile("2018212591馬俊光的用戶.txt",ios::out);
    if(!outfile)
    {
        cout<<"Save User false!";
        return;
    }
    for(int i=0;i<user.size();i++)
    {
        outfile<<user[i];
    }
    outfile.close();
    //不止要保存用戶信息,書籍信息也要重新進行調整,因為用戶可能借書或還書,書籍信息可能有所變動
    ofstream outbook("2018212591馬俊光的書籍.txt",ios::out);
    if(!outbook)
    {
        cout<<"Save Book false!";
        return;
    }
    for(int i=0;i<book.size();i++)
    {
        outbook<<book[i];
    }
    outbook.close();
    ofstream outrec("2018212591馬俊光的記錄.txt",ios::out);
    if(!outrec)
    {
        cout<<"Save record false!";
        return;
    }
    for(int i=0;i<rec.size();i++)
    {
        outrec<<rec[i];
    }
    outrec.close();
}

void Readerop::lend(int j)
{
    string in;
    cin>>in;
    int i=0;     //標記是否查到
    m=booknumber.find(in);
    if(m!=booknumber.end())
    {
        i=1;
        cout<<"Found"<<endl;   //這里算是提示,說明以下要進行輸入並操作
        cout<<book[m->second];
        string caozuo;
        while(cin>>caozuo)
        {
            if(caozuo=="jieyue"||"return")
                break;
        }
        if(caozuo=="jieyue")
        {
            if(j>0)
                cout<<"對不起,您有超期的書未歸還!"<<endl;
            else{
            int kejie=book[m->second].getKejie();
            if(user[i_].getJieyue()>=10)  //用戶不能借:用戶借書超限
            {
                //cout<<user[i_].getJieyue()<<endl;
                cout<<"以達到借閱上限"<<endl;
            }
            //判斷是否超期
            else if(book[m->second].getKejie()<=0) //書籍庫存不夠,反之則可借
            {
                cout<<"Not enough!"<<endl;
                m1=recnumber.lower_bound(book[m->second].getNumber());
                m2=recnumber.upper_bound(book[m->second].getNumber());
                for(m=m1;m!=m2;m++)
                {
                    cout<<rec[m->second];  //缺點:所有記錄都顯示了(待處理)
                }
            }
            else    //可以借閱時
            {
                //這兩個順序不可變,一定是書籍信息先變化,然后用戶信息再做調整,否則借閱的圖書是借閱之前的信息,出現錯誤
                book[m->second].setKejie(--kejie);      //書籍信息作出修改變動
                user[i_].addjieyue(book[m->second],d);  //用戶加新增書籍信息
                Record recc(book[m->second],user[i_].getName(),user[i_].getNumber(),d,"lend:");
                rec.push_back(recc);
                recnumber.insert(make_pair(recc.getBooknumber(),rec.size()-1));
            }
            cout<<user[i_];
        }
        }
        if(caozuo=="return");
    }
    if(i==0)
    cout<<"Not Found!"<<endl;
}

void Readerop::back()
{
    //還書首先要看自己借了哪本書(已借閱書籍全覽),還書的操作也是靠書號的唯一性進行掃碼還書(輸入書號進行歸還)
    //cout<<user[i_]; //登錄時就完全顯示借閱信息,這里其實不必重復顯示
    string number;
    cin>>number;
    m=booknumber.find(number);
    if(m!=booknumber.end()){//確保書籍的合理性,提高效率
    //user[i_].backjieyue(book[m->second]);
    int ii_=0;
    ii_=user[i_].backjieyue(book[m->second]);  //調了很久一開始都沒調好,原來函數在這里就被調用了,上一步的調用與之重復,當借閱重復書籍時這樣重復還書就會出現問題,把上一步的調用去掉就好了
    if(ii_==1)  //還書成功,書籍信息作出相應調整
    {
        int kejie=book[m->second].getKejie();
        book[m->second].setKejie(++kejie);
        Record recc(book[m->second],user[i_].getName(),user[i_].getNumber(),d,"back:");
        rec.push_back(recc);
    }
    }
}
//續借與還書基本一致
void Readerop::xujie(int j)
{
    if(j>0)
        cout<<"對不起,您有超期的書未歸還!"<<endl;
    else{
    int ii;
    string number;
    cin>>number;
    m=booknumber.find(number);
    if(m!=booknumber.end())
    {
        ii=user[i_].xujiejieyue(book[m->second],d);
        if(ii==1)//可續借,導入記錄
        {
            Record recc(book[m->second],user[i_].getName(),user[i_].getNumber(),d,"xujie:");
            rec.push_back(recc);
        }
    }
    }
}

class Login
{
    vector<Reader>user;
    multimap<string,int>name;
    multimap<string,int>number;
    vector<Reader>::iterator it;
    multimap<string,int>::iterator m1,m2;
public:
    Login(){load();};
    ~Login(){};
    void load();
    void login();
};

void Login::load()
{
    //重復,但是要讀取用戶信息
    Reader u;
    ifstream infile("2018212591馬俊光的用戶.txt",ios::in);
    if(!infile)
    {
        cout<<"Can't load user!"<<endl;
        return;
    }
    user.clear();
    name.clear();
    number.clear();
    while(infile>>u)
    {
        user.push_back(u);
        name.insert(make_pair(u.getName(),user.size()-1));
        number.insert(make_pair(u.getNumber(),user.size()-1));
    }
    infile.close();
}

void Login::login()
{
    string name_,number_;
    int i=0;
    cout<<"請輸入賬號,密碼:"<<endl;  //用戶端賬號即姓名,密碼即借閱號(學號)(密碼沒有必要變動)(刷卡)
    cin>>name_>>number_;
    if(name_=="xiaoguang"&&number_=="123")
    {
        i=1;
        //調用管理端
        Guanliop guanli;
        //管理端的任意操作:(其實使用菜單會方便一些(便於操作))
        /* guanli.addBook(); guanli.addReader(); guanli.openBook(); guanli.openReader(); guanli.openRecord(); guanli.setBook(); guanli.setReader(); */

    }
    m2=number.find(number_);
    if(m2!=number.end())
    {
        i=1;
        //登錄日期暫時由人為輸入
        cout<<"請輸入登錄日期:"<<endl;
        Data d;
        cin>>d;
        Readerop reader(m2->second,d);
        cout<<reader.getUser();
        cout<<"Welcome back!"<<endl;  //必須輸對有效的日期才行
        //判斷是否存在書籍超期現象:
        int j=user[m2->second].chaoqi(d);  //對於超期的不可借閱不可續借
        //Readerop reader(m2->second,d);
       // readerop(m2->second,d);
        //調用用戶端
        reader.search();
        reader.search();
        reader.lend(j);
        reader.lend(j);
        reader.xujie(j);
        reader.back();
    }
    if(i==0)
    cout<<"賬號或密碼輸入有誤"<<endl;
}
//登錄


int main()
{
    //登錄后進行的操作:每次登錄:兩次搜索,兩次借閱,一次續借,一次還書
    Login op;
    int n=3;
    while(n--)
    op.login();
    return 0;
}

需要的文件:

2018212591馬俊光的用戶.txt
name: 馬俊光 number: 2018212591 yijie: 2 kejie: 8
jieshuxinxi:
book.name: 《高等數學指導》 writer: 李仁所 book.number: 001 book.press: 清華大學出版社 book.publishdata: 2019 5 20 zongshu: 10 kejie: 7 guancang.not.lend: 2
lend: 2019 1 10 back: 2019 2 9 xujie: 0
book.name: 《向死而生》 writer: 李開復 book.number: 003 book.press: 人民郵電出版社 book.publishdata: 2019 5 1 zongshu: 7 kejie: 4 guancang.not.lend: 2
lend: 2019 1 10 back: 2019 2 9 xujie: 1
name: 孫林 number: 2018212488 yijie: 0 kejie: 10
name: 黃敬中 number: 2018212598 yijie: 0 kejie: 10
name: 郎豐通 number: 2018212543 yijie: 0 kejie: 10
name: 常凱 number: 2018212555 yijie: 0 kejie: 10
2018212591馬俊光的書籍.txt
book.name: 《高等數學指導》 writer: 李仁所 book.number: 001 book.press: 清華大學出版社 book.publishdata: 2019 5 20 zongshu: 10 kejie: 7 guancang.not.lend: 2
book.name: 《高等數學指導》 writer: 王志武 book.number: 002 book.press: 北京大學出版社 book.publishdata: 2019 5 21 zongshu: 6 kejie: 3 guancang.not.lend: 3
book.name: 《向死而生》 writer: 李開復 book.number: 003 book.press: 人民郵電出版社 book.publishdata: 2019 5 1 zongshu: 7 kejie: 4 guancang.not.lend: 2
book.name: 《挑戰程序設計》 writer: 巫澤俊 book.number: 004 book.press: 人民郵電出版社 book.publishdata: 2010 1 1 zongshu: 8 kejie: 6 guancang.not.lend: 2
book.name: 《原則》 writer: 瑞·達利歐 book.number: 005 book.press: 人民文學出版社 book.publishdata: 2011 2 2 zongshu: 7 kejie: 5 guancang.not.lend: 2
book.name: 《英語美文閱讀》 writer: 高珊 book.number: 006 book.press: 人民文學出版社 book.publishdata: 2012 3 3 zongshu: 12 kejie: 10 guancang.not.lend: 2
book.name: 《中國近代史綱要》 writer: 王書君 book.number: 007 book.press: 北京大學出版社 book.publishdata: 2013 4 4 zongshu: 15 kejie: 8 guancang.not.lend: 7
book.name: 《電子電路技術》 writer: 殷瑞祥 book.number: 008 book.press: 高等教育出版社 book.publishdata: 2014 5 5 zongshu: 6 kejie: 5 guancang.not.lend: 1
2018212591馬俊光的記錄.txt
lend: username: 馬俊光 usernumber: 2018212591
book.name: 《高等數學指導》 writer: 李仁所 book.number: 001 book.press: 清華大學出版社 book.publishdata: 2019 5 20 zongshu: 10 kejie: 7 guancang.not.lend: 2
2019 1 1
lend: username: 馬俊光 usernumber: 2018212591
book.name: 《高等數學指導》 writer: 王志武 book.number: 002 book.press: 北京大學出版社 book.publishdata: 2019 5 21 zongshu: 6 kejie: 2 guancang.not.lend: 3
2019 1 1
back: username: 馬俊光 usernumber: 2018212591
book.name: 《高等數學指導》 writer: 李仁所 book.number: 001 book.press: 清華大學出版社 book.publishdata: 2019 5 20 zongshu: 10 kejie: 8 guancang.not.lend: 2
2019 5 1
xujie: username: 馬俊光 usernumber: 2018212591
book.name: 《高等數學指導》 writer: 王志武 book.number: 002 book.press: 北京大學出版社 book.publishdata: 2019 5 21 zongshu: 6 kejie: 2 guancang.not.lend: 3
2019 1 10
lend: username: 馬俊光 usernumber: 2018212591
book.name: 《高等數學指導》 writer: 李仁所 book.number: 001 book.press: 清華大學出版社 book.publishdata: 2019 5 20 zongshu: 10 kejie: 7 guancang.not.lend: 2
2019 1 10
lend: username: 馬俊光 usernumber: 2018212591
book.name: 《向死而生》 writer: 李開復 book.number: 003 book.press: 人民郵電出版社 book.publishdata: 2019 5 1 zongshu: 7 kejie: 4 guancang.not.lend: 2
2019 1 10
xujie: username: 馬俊光 usernumber: 2018212591
book.name: 《向死而生》 writer: 李開復 book.number: 003 book.press: 人民郵電出版社 book.publishdata: 2019 5 1 zongshu: 7 kejie: 4 guancang.not.lend: 2
2019 1 10
back: username: 馬俊光 usernumber: 2018212591
book.name: 《高等數學指導》 writer: 王志武 book.number: 002 book.press: 北京大學出版社 book.publishdata: 2019 5 21 zongshu: 6 kejie: 3 guancang.not.lend: 3
2019 1 10
result部分解釋:

在這里插入圖片描述
代碼中之前的注釋部分刪掉了。
先登錄,按出版日期查詢了一次,按索書號查詢了一次,借書借了兩本,續借一本還書一本(可見記錄)
對於繼承:這里只對查詢進行了簡單繼承(寫的能實現功能,但是不好,沒有將書籍查詢單獨列為一個大類,就當做對繼承的練習,繼承的大體使用:通過調用基類函數實現派生類中相對重復的功能)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM