最近终于写了一个让自己满意的系统,我在这里分享一下,顺便总结一下自己的学习心得。

1.需求分析
听的好像是要做项目一样,但是无论写什么程序,些什么系统,都是要知道自己要干什么,要完成什么工作,实现那些功能,在这前列出一个表格,或是思维导图,给自己一个方向,先规划好再写,不然会拉下很多东西,在我写这个系统之前,我在图书馆的借书页面,看了将近两个小时,中途又看了好多次,这次代码不能说是一个完美可以当作工程性的使用,其中还有很多测试环节,还有部分功能没有实现,比如二次检索,三次检索功能,数据少得可怜,肯定还有一些未知的错误,所以我在这里真是分享我写代码,及调试代码的方法跟过程。
2.写代码+调试代码
写代码的时候一定要写一个功能调试一个功能,所谓的一个功能不是一个类,而是一个类的一个函数,如果一个函数会影响到其他函数的运行,不调好之前的函数,现在的函数也没法运行,当代码随着项目的增大,代码长度几何增长是,再找错误就很难的了,所以顺着调试下去,以便你写完的代码是可以运行的,是正确的,而具体能否实现功能在另说。
数据类与操作类的分离,面向对象要的是封装性,操作抽象+数据抽象,继承,写代码写完能够复用最好,乱糟糟的写完不能复用的类扔在那里,以后再也不会用到,浪费时间,完全可以写一些代码条理清晰,更重要的是,下次相似的代码不用再继续写,这应该是应该具备的素养。
以下是我调试代码的过程,最后代码还是有一点错误,这里是我的明明还是不好的原因,补充一下我认为明明一定要有意义,可以将学生的每科学分定义为a b c d. …也可以定义为数学 英语 物理 c++…这样可以增加代码的可读性。
引以为戒:
下文中这两个MAP混用导致了一些问题,以至于我交代码的时候是错误的还有没有发现

map<string,int>idtorea;  //读者id对应读者数据下标
map<string ,int> idtoob; //图书id对应图书数据下标

时间类
图书馆管理系统用户端心得-编程之家
时间类第一次调试运行,测试有参无参,重载<< ,>>和+
图书馆管理系统用户端心得-编程之家

写到后边发现,自己重载的+错了,而且还需要计算两个时间类相差的时间,回头从新写的重载+,跟-

图书类
图书馆管理系统用户端心得-编程之家
这里调试很多遍,开始留了一个应还时间Time类,后来发现,没有用。
图书馆管理系统用户端心得-编程之家
后来想到,可能查询归还时间,所以写了get函数,但是函数不能反回局部类对象,只好写成static。
图书馆管理系统用户端心得-编程之家
因为后边的时候需要输出,但是有些数据只有管理员能够看到,所以写完后边的回来写的print函数。
读者类
图书馆管理系统用户端心得-编程之家
这里学生能做的事情不多,修改密码,查询个人信息,别的都做不了。

图书馆管理系统用户端心得-编程之家
在后边实现借书就要在数据类中实现更改,所以在这里加了一条进行测试所添加的操作。
操作数据类
图书馆管理系统用户端心得-编程之家
每一条新数据都必须,拥有参初始化,除了文件读取除外。
图书馆管理系统用户端心得-编程之家
操作类也面临着不能直接输出的尴尬境界,所以回来,再写一个print。
图书馆管理系统用户端心得-编程之家
终于看到自己的程序成功运行,也试了几组错误情况。基本无问题。

#include<bits/stdc++.h.>
using namespace std;
class Time
{int  year,month,day;
public:Time(){loadtime();}Time(int y,int m,int d):year(y),month(m),day(d){};    //用与图书出版日期等已知数据的对象的初始化;//不能创建图书对象,有参初始化就没意义。//  Time(Time & a){year=a.year,month=a.month,day=a.day;}    //用一个时间类初始化一个时间类,为后续操作准备;//这句不注释就没法运行,不得解void loadtime();    //定义时间获取函数,学生借书的时间不可更改,直接从系统读入;friend istream & operator>>(istream &in,Time & a);  //不设置set函数,时间直接一次性全部修改即可;friend stringstream & operator>>(stringstream &in,Time & a);friend ostream & operator<<(ostream &out,Time & a);bool operator <(const Time &d)const{    //重载小于号,用于数据时间排序,不需要修改数据const;return year!=d.year?year<d.year:month!=d.month?month<d.month:day<d.day;}int judge() const;  //判断是否为闰年,用于续借日期的变化;int judge(int year) const ;//写一个有参的判断函数;Time operator +(int  a) ;   //重载加号,用于续借日期的变化;friend int operator -(Time a,Time b);  //计算两段时间间隔;
};
Time Time::operator +(int  a)
{int m[] = {0,31,28,31,30,31,30,31,31,30,31,30,31};day+=a;int flag=1;while(day>m[month]){if(month==2){if(day>m[month]+judge()){day-=m[month]+judge();month++;}}else {day=day-m[month];month++;}//因为一对大括号跑了好几遍,敲ACM也一样,不要偷懒if(month>12){month-=12;year++;}}
}
int operator -(Time a,Time b)
{int monthdays[2][12] = { { 31,28,31,30,31,30,31,31,30,31,30,31 },{ 31,29,31,30,31,30,31,31,30,31,30,31 } };int yeardays[2] = { 365,366 };int sumdays=0;if (a.year == b.year&& a.month == b.month){sumdays = b.day - a.day;}elseif (a.year == b.year){sumdays += monthdays[a.judge(a.year)][a.month-1] - a.day;for (int i = a.month; i < b.month-1; i++)sumdays += monthdays[a.judge(a.year)][i];sumdays += b.day;}else{sumdays += monthdays[a.judge(a.year)][a.month-1] - a.day;for (int i = a.month; i < 12; i++)sumdays += monthdays[a.judge(a.year)][i];for (int i = a.year + 1; i < b.year; i++)sumdays += yeardays[a.judge(i)];for (int i = 0; i < b.month - 1; i++)sumdays += monthdays[a.judge(b.year)][i];sumdays += b.day;}return sumdays;
}
int Time::judge() const{if(year % 4 == 0 && year %100 != 0 ||year % 400 == 0) return 1;else return 0;
}
int Time::judge(int year) const{if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)return 1;else  return 0;
}
void Time::loadtime(){time_t rawtime;struct tm *ptminfo;time(&rawtime);ptminfo = localtime(&rawtime);year=ptminfo->tm_year + 1900;month=ptminfo->tm_mon + 1;day=ptminfo->tm_mday;
}
istream & operator>>(istream &in,Time & a){in>>a.year>>a.month>>a.day;return in;
}
ostream & operator<<(ostream &out,Time & a)
{out<<a.year<<" "<<a.month<<" "<<a.day<<" ";return out;
}
stringstream & operator>>(stringstream &in,Time & a){in>>a.year>>a.month>>a.day;return in;
}
/*
int main()
{Time  demo1;//无参初始化对象cout<<demo1<<endl;Time demo2(demo1);//有参初始化对象,便于不同时间定义对象,时间不同;cout<<demo2<<endl;demo2+60;//为续借,即还书时间做准备;cout<<demo2;Time demo3(2000,03,19);cout<<demo3<<endl;
}
*/
/*
int main()
{Time demo1,demo2;cin>>demo1>>demo2;int d=demo1-demo2;demo1+d;cout<<demo1<<endl;cout<<d<<endl;
}*/
class Book
{string name;string  press;                                                             //出版社string pubtime;                                                     //出版时间通常在图书馆只有年份string author;                                                      //作者string suoshu;                                                     //索书号string id;          //每本书都有唯一的条形码,两本完全一样的书,在这里应该看作两本书string locate;string jsr;            //指向借书人数据在的位置的下标(-1),代表可借int fk;       //每本书都有自己的罚款,不会影响其他书籍,定义在这里比定义在读者类要合适bool xj;   //比起写入记录中查询,写在图书中,无论是还书,还是续借,都更加便捷Time jy;//   Time rebac;
public:Book():name(""),press(""),author(""),id(""),suoshu(""),locate(""),jsr("-1"),fk(0){}//学生端不能创建书籍对象,只写一个无参初始化,用于读取文件数据;string getname ()const{return name;}string getpress ()const{return press;}string getauthor ( )const{return author;}string getpubtime ( )const{return pubtime;}string getid ( )const{return id;}string getsuoshu ( )const{return suoshu;} //通过上述get函数为下面的查询做准备;int getfk(){jsfk();return fk;}void xxj(){/*if(fk<=0)xj=!xj;else cout<<"请先缴清罚款"<<endl;*/ //改为在读者类判断,不只是一本书的罚款,会影响借书;xj=!xj;}bool getxj(){  return xj;}void js(string idcard){jsr=idcard;}             //学号跟图书的条形码是唯一的,由此来对应;Time& getreback();void jsfk();void print();friend istream & operator>>(istream &in,Book & a);friend ostream & operator<<(ostream &out,Book & a);
};
void Book::jsfk()
{int brr;if(xj) brr=120;else brr=60;Time tem;fk=tem-jy-brr;if(fk<0) fk=0;
}
void Book::print()
{cout<<name<<" "<<press<<" "<<author<<" "<<id<<" "<<suoshu<<" "<<locate<<" ";if(jsr!="-1") cout<<"已借出  归还时间:"<<getreback()<<endl;else cout<<endl;
}
Time& Book::getreback(){static Time tem(jy);tem+60*(1+getxj());return tem;
}
istream & operator>>(istream &in,Book & a){in>>a.name>>a.press>>a.pubtime>>a.author>>a.suoshu>>a.id>>a.jsr>>a.locate>>a.jy>>a.xj;return in;
}
ostream & operator<<(ostream &out,Book & a){out<<a.name<<" "<<a.press<<" "<<a.pubtime<<" "<<a.author<<" "<<a.suoshu<<" "<<a.id<<" "<<a.jsr<<"  "<<a.locate<<" "<<a.jy<<" "<<a.xj;return out;
}
//记 北京机械工业出版社 2016 胡凡 TP301.6/H569 01664298  123456 -1 采编部在编 2018 5 16  1
/*
int main()
{Book demo;cin>>demo;cout<<demo;cout<<demo.getname()<<endl;cout<<demo.getpress()<<endl;cout<<demo.getauthor()<<endl;cout<<demo.getsuoshu()<<endl;cout<<demo.getpubtime()<<endl;cout<<demo.getfk()<<endl;int jsr;cin>>jsr;demo.js(jsr);cout<<demo.getxj()<<endl;demo.xxj();cout<<demo.getxj()<<endl;cout<<demo<<endl;
} //算法笔记 北京机械工业出版社 2016 胡凡 TP301.6/H569 01664298  123 采编部在编 2018 5 16  1
*/
/*
int main()
{Book demo;cin>>demo;cout<<demo.getreback();
}*/
/*
int main()
{Book  demo1;//无参初始化对象cin>>demo1;demo1.print();
}
*/
class Student
{string name;string id;string key;string mail;vector<string> jy;/*按时间先后借的书,则为有序,int是图书数据的ID;通过下标联通了图书与读者。*/int yj;//已借图书
public:Student() :name(""),id(""),key(""),mail(""){jy.clear();}//void printxx() 想写打印信息的功能,但是目前这个类看不到图书数据,无法关联。转而写get函数;vector<string> getjy() const{return jy;}         //先返回一个vector对象,目前看不到图书数据,所以返回后,在操作类中使用string getname(){return name;}string getid(){return id;}string getkey(){return key;}string getmail(){return mail;}int getyj()const {return yj;}void setkey(string tem) ;           //修改密码void  jieyue(string obid);     //借阅图书,图书馆的借阅最后都是按照书的唯一的条码来借阅void reback(string obid);      //归还同上。/*现在看不到图书数据,只能写出部分借阅,归还操作,在操作类中应判断是否具有罚款,此函数仅用于修改学生,作为子函数使用*/friend istream & operator>>(istream &in,Student & a);friend ostream & operator<<(ostream &out,Student & a);
} ;
istream & operator>>(istream &in,Student & a)
{in>>a.name>>a.id>>a.key>>a.mail>>a.yj;string tem;for(int i=0;i<a.yj;i++) {in>>tem;a.jy.push_back(tem);}return in;
}
ostream & operator<<(ostream &out,Student & a)
{out<<a.name<<" "<<a.id<<" "<<a.key<<" "<<a.mail<<" "<<a.yj<<" ";for(int i=0;i<a.yj;i++) cout<<a.jy[i]<<" ";return out;
}
void Student::jieyue(string obid)
{if(yj>=10) cout<<"借阅数量已达上限"<<endl;else jy.push_back(obid);yj=jy.size();
}
void Student::reback(string obid)    //归还操作很宽泛,甚至都不需要登陆账号,但是根据图书找到人,最后还是要根据id在这人身上去掉
{//不需要容错,如果系统不崩溃,从书籍查借人一定是唯一的auto po=find(jy.begin(),jy.end(),obid);if(po==jy.end()) cout<<"还书失败,请联系管理员"<<endl;else jy.erase(po);yj=jy.size();
}
void Student::setkey(string tem)
{while(tem!=key){cout<<"密码错误,请重试"<<endl;cin>>tem;}cin>>tem;key=tem;
}
/*
int main()
{Student demo;cin>>demo;cout<<demo.getname()<<endl;cout<<demo.getid()<<endl;cout<<demo.getkey()<<endl;cout<<demo.getmail()<<endl;cout<<demo.getyj()<<endl;cout<<demo;
}*/
//张俊浩  2018212513 123456 529934209@qq.com  1  203
/*
int main()
{string tem;Student demo;cin>>demo>>tem;demo.jieyue(tem);cout<<demo<<endl;cin>>tem;demo.reback(tem);cout<<demo;
}
*/class Operate //记录只能生成不能修改
{Time time;string oper; //操作string peo; //操作人idstring boo; //图书对象IDint fk;    //当操作为还书时有真实罚款,其余为-1
public:Operate( ):oper(""),peo(""),boo(""),fk(-1){}   //仅用于文件读写Operate(string o,string p,string b,int c):oper(o),peo(p),boo(b),fk(c){time.loadtime();}  //操作无论管理员,学生都无法改变时间;string getname(){return peo;}string getbook(){return boo;}string getoper(){return oper;}int getfk(){return fk;}          // 用于后续查询操作void print() ;friend istream & operator>>(istream &in,Operate & a);friend ostream & operator<<(ostream &out,Operate & a);
} ;
void Operate::print()
{cout<<time<<" "<<peo<<" "<<oper<<" "<<boo<<" ";if(fk!=-1) cout<<"缴纳罚款:"<<fk<<endl;
}
istream & operator>>(istream &in,Operate  & a)
{in>>a.time>>a.peo>>a.oper>>a.boo>>a.fk;return in;
}
ostream & operator<<(ostream &out,Operate  & a)
{out<<a.time<<" "<<a.peo<<" "<<a.oper<<" "<<a.boo<<" "<<a.fk<<" ";return out;
}
/*
int main()
{Operate demo;cin>>demo;cout<<demo.getname()<<" "<<demo.getoper()<<" "<<demo.getbook()<<" "<<demo.getfk()<<endl;cout<<demo<<endl;string name,op,ob;int fk;cin>>name>>op>>ob>>fk;Operate demo2(name,op,ob,fk);cout<<demo2<<endl;
}
*/
/*
int main()
{Operate demo;cin>>demo;demo.print();
}*/
class  Library
{string account;string password;      //每次登入图书馆进行操作都要有账号密码vector<Book>  book;vector<Student> reader;vector<Operate> record;   //三个基础数据;//图书查询操作所需数据multimap<string,int> pubtimque;   //出版时间multimap<string,int> suoshuque;   // 索书号multimap<string,int> pressque;   //出版社//书名与作者都需要模糊查询//数据查询map<string,int>idtorea;  //读者id对应读者数据下标map<string ,int> idtoob; //图书id对应图书数据下标multimap<string,int> ridtorec; //读者Id对应操作数据下标multimap<string,int> bidtorec; //图书 id对应操作数据下标
public:Library(string ac,string pass): account(ac),password(pass){load();login();cout<<book.size();}void login();//书籍查询操作void querysm(string name) ;//书名查询void queryss(string suoshu) ; //索书号查询void queryath(string ath); //作者查询void querypres(string pre); //出版社查询void querytim(string pub);//出版时间查询//个人信息操作void quepers();  //查询读者身份信息void quebrro();//查询借阅信息void queop(); //查询读者操作记录(仅个人)//基础操作int cxkj(); //查询课可借书的数量void jieshu(string id) ;void huanshu(string id);void xujie(string id);   //图书馆虽然不用输入书的条码,但是现在也是通过书的磁获取//也应该看是输入,比如某些地方仍用扫码,甚至手输void load();void save();~Library(){save();}
};
//有些map是给管理端用的,这里只写不读;
void Library::login()
{while(1){auto po=idtorea.find(account);if(po!=idtorea.end()&&reader[po->second].getkey()==password) break;cout<<"账号密码不匹配n请重新输入n";    //可以在分个账号不存在,但看很多网站,//都不会报不存在,为了提高一点安全性;cin>>account>>password;}cout<<"登陆成功n";
}
void Library:: querysm(string name)
{for(auto po=book.begin();po!=book.end();po++){auto m=po->getname().find(name);if(m!=-1) po->print();}
}
void Library::  queryss(string suoshu)
{auto beg=suoshuque.lower_bound(suoshu);auto en=suoshuque.upper_bound(suoshu);for(auto po=beg;po!=en;po++)book[po->second].print();
}
void Library::  queryath(string ath){for(auto po=book.begin();po!=book.end();po++){auto m=po->getauthor().find(ath);if(m!=-1) po->print();}
}
void Library::  querypres(string pre)
{auto beg=pressque.lower_bound(pre);auto en=pressque.upper_bound(pre);for(auto po=beg;po!=en;po++)  book[po->second].print();
}
void Library::  querytim(string pub)
{auto beg=pubtimque.lower_bound(pub);auto en=pubtimque.upper_bound(pub);for(auto po=beg;po!=en;po++)book[po->second].print();
}
void Library::  quepers(){cout<<reader[idtoob[account]].getname()<<" ";cout<<reader[idtoob[account]].getid()<<" ";cout<<reader[idtoob[account]].getmail()<<" ";cout<<reader[idtoob[account]].getyj()<<" ";cout<<cxkj()<<endl;
}
void Library::  quebrro()
{for(auto po=reader[idtoob[account]].getjy().begin();po!=reader[idtoob[account]].getjy().end();po++)book[idtoob[ *po]].print();
}
void Library::  queop()
{auto beg=ridtorec.lower_bound(account);auto en=ridtorec.upper_bound(account);for(auto po=beg;po!=en;po++)record[po->second].print();
}
int Library:: cxkj()
{int ans=0;for(auto po=reader[idtoob[account]].getjy().begin();po!=reader[idtoob[account]].getjy().end();po++)ans+=book[idtoob[ *po]].getfk();if(ans>0) return -1;else return 10-reader[idtoob[account]].getjy().size();
}
void Library:: jieshu(string id)
{if(cxkj()==-1){  cout<<"归还逾期,请先归还n"; return ;}else if(cxkj()==0) {  cout<<"达到借书上限n"; return ;}reader[idtorea[account]].jieyue(id);book[idtoob[id]].js(account);Operate tem("借书",account,id,-1);record.push_back(tem);ridtorec.insert(make_pair(account,record.size()-1));bidtorec.insert(make_pair(id,record.size()-1));
}
void Library:: huanshu(string id)
{reader[idtorea[account]].reback(id);//异常在 reback抛出book[idtoob[id]].js("-1");int money=book[idtoob[id]].getfk();Operate www("还书",account,id,money);record.push_back(www);ridtorec.insert(make_pair(account,record.size()-1));bidtorec.insert(make_pair(id,record.size()-1));
}
void Library:: xujie(string id)
{if(cxkj()==-1){  cout<<"归还逾期,请先归还n"; return ;}else if(cxkj()==0) {  cout<<"达到借书上限n"; return ;}book[idtoob[id]].xxj();Operate tem("续借",account,id,-1);record.push_back(tem);ridtorec.insert(make_pair(account,record.size()-1));bidtorec.insert(make_pair(id,record.size()-1));
}
void Library::save()
{ofstream out1("d:\book.txt",ios::out);for(auto po=book.begin(); po!=book.end(); po++)out1<<*po<<endl;out1.close();ofstream out2("d:\reader.txt",ios::out);for(auto po=reader.begin(); po!=reader.end(); po++)out2<<*po<<endl;out2.close();ofstream out3("d:\record.txt",ios::out);for(auto po=record.begin(); po!=record.end(); po++)out3<<*po<<endl;out3.close();
}
void Library:: load()
{ifstream in1("d:\book.txt",ios::in);if(in1){Book tem1;book.clear();while(in1>>tem1){book.push_back(tem1);idtorea.insert(make_pair(tem1.getid(),book.size()-1));pubtimque.insert(make_pair(tem1.getpubtime(),book.size()-1));suoshuque.insert(make_pair(tem1.getsuoshu(),book.size()-1));pressque.insert(make_pair(tem1.getpress(),book.size()-1));}in1.close();}ifstream in2("d:\reader.txt",ios::in);if(in2){reader.clear();Student tem2;while(in2>>tem2){reader.push_back(tem2);idtorea.insert(make_pair(tem2.getid(),reader.size()-1));}in2.close();}ifstream in3("d:\record.txt",ios::in);if(in3){record.clear();Operate tem3;while( in3>>tem3){record.push_back(tem3);ridtorec.insert(make_pair(tem3.getname(),record.size()-1));bidtorec.insert(make_pair(tem3.getbook(),record.size()-1));}in3.close();}
}
int main()
{string account,key,name,suoshu,ath,pre,pub,id;cin>>account>>key;Library demo(account,key);cin>>name;demo. querysm( name) ;//测试书名查询cin>>suoshu;demo.   queryss( suoshu) ; //测试索书号查询cin>>ath;demo. queryath( ath); //测试作者查询cin>>pre;demo.   querypres( pre); //测试出版社查询cin>>pub;demo. querytim( pub);//测试出版时间查询//测试个人信息操作demo. quepers();  //测试查询读者身份信息demo.   quebrro();//测试查询借阅信息demo.  queop(); //测试查询读者操作记录(仅个人)//测试基础操作demo. cxkj(); //测试查询课可借书的数量cin>>id;demo.   jieshu( id) ;cin>>id;demo.   huanshu( id);cin>>id;demo.   xujie( id);return 0;
}