实验目的 构建一个图书馆系统,包含
1.类$BookRecord$,对单本数记录,记录内容为书籍编号,书籍名,书籍作者,出版年份,可借阅量,已借出量
2.类$Borrower$,对借阅者进行登记,登记内容为姓名,身份id,借书量,书籍编号信息
3.类$Catalogue$,访问上述两个类,即实现对已存书的访问和对借书人的访问
4.类$Library$,作为整个系统的载体,后续添加额外功能需要从此入手
实验过程 以实验目的的顺序完成图书馆的构建
$BookRecord$ BookRecord::BookRecord () { book_ava_num=0 ; book_loan=0 ; };
初始化,将存书和借书数目默认为0
BookRecord::BookRecord (string i, string t, string a, string y, int n, int l) : book_id (i), book_title (t), book_auther (a), book_year (y), book_ava_num (n), book_loan (l){ if (book_id[0 ] < 65 || book_id[0 ] > 90 ) { cout << "书籍ID错误" << endl; exit (0 ); } if (book_year[0 ] < 49 || book_id[0 ] > 50 ) { cout << "出版时间错误" << endl; exit (0 ); } if (book_id.length () != 4 ) { cout << "书籍ID错误" << endl; exit (0 ); } };
含参构造,为单个书提供直接输入的构造函数,同时完成对ID,year的判断
BookRecord::~BookRecord (){};
析构函数
void BookRecord::write (ifstream &ifs) { getline (ifs,book_id,';' ); cout<<book_id; cout<<book_id.length ()<<endl; if (book_id[1 ] < 65 || book_id[1 ] > 90 ) { cout << "书籍FID错误" << endl; exit (0 ); } if (book_id.length () != 5 ) { cout << "书籍LID错误" << endl; exit (0 ); } getline (ifs, book_title,';' ); getline (ifs, book_auther,';' ); getline (ifs,book_year,';' ); if (book_year[0 ] < 49 || book_id[0 ] > 50 ) { cout << "出版日期错错误" << endl; exit (0 ); } ifs >> book_ava_num; ifs >> book_loan; }
写入数据,在后续创建类$BookRecord$的数组时,需要此函数通过ifstream获取文件中的数据
此外,在输入完成后,对ID,year进行判断是否合法,如不合法,使用exit(0)退出
string BookRecord::id () { return book_id; } string BookRecord::return_ID () { return book_id; }
返回private的成员值
void BookRecord::write_booknum () { book_ava_num--; if (book_ava_num < 0 ) { cout << "书库殆尽,无法借阅" << endl; book_ava_num = 0 ; } } void BookRecord::write_bookloan () { book_loan++; }
为单本图书的借阅提供接口,并判断合法性
void BookRecord::check () { cout << "Book ID :" << book_id << endl; cout << "Title :" << book_title << endl; cout << "Author :" << book_auther << endl; cout << "Year published :" << book_year << endl; cout << "Total number of copies :" << book_ava_num << endl; cout << "Number available for loan :" << book_loan << endl; }
返回类中记录的所有数据,用于检查书籍完全度
$Borrower$ Borrower::Borrower () { loan=0 ; loan_books=NULL ; };
默认构造,将动态数组设置为空,等待后续赋值
Borrower::Borrower (string i, string b, int l) : borrower_id (i), borrower (b), loan (l) { if (borrower_id.length () != 5 ) { cout << "借阅人ID错误" << endl; exit (0 ); } };
为单位人的借阅提供接口
void Borrower::write (ifstream& ifs) { getline (ifs, borrower_id,';' ); cout<<borrower_id.length (); if (borrower_id.length () != 6 ) { cout << "用户ID错误" << endl; exit (0 ); } getline (ifs, borrower,';' ); ifs >> loan; createbook (loan); readbook (ifs); }
传入ifstream&,输入对应的数据并创建动态数组,转至readbook中继续读取
void Borrower::readbook (ifstream& ifs) { for (int i = 0 ; i < loan; i++) { getline (ifs,loan_books[i],';' ); cout<<loan_books[i]; cout<<loan_books[i].length ()<<endl; if (loan_books[i][1 ] < 65 || loan_books[i][1 ] > 90 ) { cout << "书籍ID错误" << endl; exit (0 ); } } }
传入ifstream&,从文件中读取借阅人的书籍数据,同时对书籍的编号判断合法性
void Borrower::createbook (int a) { loan=a; loan_books=new string[loan]; }
创建动态数组的函数
string Borrower::bookid (int i) { if (i>loan) exit (0 ); else return loan_books[i]; } int Borrower::loan_bor () { return loan; } void Borrower::return_id () { for (int i = 0 ; i < loan; i++) { cout << loan_books[i] << " " ; } cout << endl; }
返回借书的编号,用于和BookRecord比对,然后借阅,第一个为单个查看,后两个为依此查看
void Borrower::check () { cout << "借阅人ID :" << borrower_id << endl; cout << "姓名 :" << borrower << endl; for (int i = 0 ; i < loan; i++) { cout << "第 " << i << " 个 :" ; cout << "借出书的数目 :" << loan_books[i] << endl; } }
返回借阅人全部信息的函数
Borrower::~Borrower () { delete [] loan_books; };
记得对动态数组进行释放
$Catalogue$ Catalogue::Catalogue () { book_total = 0 ; book_borrow=0 ; bookres = NULL ; bor=NULL ; }
初始构造,将两个动态数组都设置为空
void Catalogue::writebook (int & a) { book_total = a; } void Catalogue::writeloan (int & a) { book_borrow = a; }
写入书籍书和借阅人数的函数
void Catalogue::create_record (ifstream &ifs) { bookres = new BookRecord[book_total]; for (int i = 0 ; i < book_total; i++) { bookres[i].write (ifs); } }
创建BookRecord的动态数组,并调用write完成写入数据
void Catalogue::create_borrow (ifstream &ifs) { bor = new Borrower[book_borrow]; for (int i=0 ; i<book_borrow; i++) { bor[i].write (ifs); find_record (bookres, bor[i]); } }
创建Borrower的动态数组,并调用write完成写入借阅人和借阅数的数据
void Catalogue::find_record (BookRecord a[], Borrower b) { int borrow_num = b.loan_bor (); for (int i = 0 ; i < book_borrow; i++) { for (int j = 0 ; j < borrow_num; j++) { if (a[i].id () == b.bookid (j)) { a[i].write_bookloan (); a[i].write_booknum (); } } } } void Catalogue::find_ID (BookRecord a[], string id) { for (int i = 0 ; i < book_total; i++) { if (a[i].return_ID () == id) a[i].check (); } }
获取借阅书的数目后循环访问BookRecord数组,以完成对可借阅书的数目的操作
BookRecord* Catalogue::re_bookres () { return bookres; } Borrower* Catalogue::re_borrow () { return bor; }
返回相关数据
Catalogue::~Catalogue () { delete bookres; delete bor; }
释放内存
$Library$ Library::Library (int a, int b) : books (a), loan (b){};
含参构造,对存书量和借阅量赋值
Library::Library () { loan=0 ; books=0 ; };
默认构造,初始化
void Library::write_book (ifstream &ifs) { ifs >> books; cout<<"记载了" <<books<<"本书" <<endl; }; void Library::write_loan (ifstream &ifs) { ifs >> loan; cout<<"记载了" <<loan<<"个借阅人" <<endl; };
根据ifs的输入提示相应的行为
int & Library::getbooks () { return books; } int & Library::getloan () { return loan; } void Library::lookbook (int a) { cata.re_bookres ()[a].check (); } void Library::lookborrow (int a) { cata.re_borrow ()[a].check (); } Catalogue& Library::re_cltalogu () { return cata; }
返回信息函数,第三四函数返回catalougue的两个对象的相关数据
$ifstream$ 该段主要为文件操作部分
$ifstream$ ifstream ifs; ifs.open ("date.txt" , ios::in); if (ifs.is_open ()){ library.write_book (ifs,ofs); library.write_loan (ifs,ofs); library.re_cltalogu ().writebook (library.getbooks ()); library.re_cltalogu ().writeloan (library.getloan ()); library.re_cltalogu ().create_record (ifs); library.re_cltalogu ().create_borrow (ifs); for (int i=0 ;i<library.getbooks ();i++) library.re_cltalogu ().re_bookres ()[i].check (ofs); } ifs.close ();
创建对象后打开文件$ifs.open(“date.txt”, ios::in)$,接着用$ifs.is_open()$检查是否打开文件。若打开,则以&的方式传入函数进行输入。
在Library.cpp中开输入流对象,能有效缩小开销。 建议写完之后close文件 使用”\n“作为getline的标准会导致问题,经常出现只读一半的问题,改为$getline(ofs,line,’;’)$后就便成为空格读取不当的问题(这问题在读取到换行符时也会出现),需要手动在文件中添加空格,如需对读取的内容进行判断,还要删去空格。
当前样式 N123;Object-Oriented Programming;Dave Smith;2009;3 1 先前样式 N123 Object-Oriented Programming Dave Smith 2009 3 1 但是,在对不含空格的一行使用getline时会出现跨行读取的问题。故使用ifs>>读取
$ofstream$ ofstream ofs ("out.txt" ) ;ifs.open ("date.txt" , ios::in); if (!ofs.is_open ()){ cout<<"文件打开失败" <<endl; return 0 ; } if (ifs.is_open ()){ library.write_book (ifs,ofs); library.write_loan (ifs,ofs); library.re_cltalogu ().writebook (library.getbooks ()); library.re_cltalogu ().writeloan (library.getloan ()); library.re_cltalogu ().create_record (ifs); library.re_cltalogu ().create_borrow (ifs); for (int i=0 ;i<library.getbooks ();i++) library.re_cltalogu ().re_bookres ()[i].check (ofs); } ofs.close ();
创建输出流对象,$out.txt$若存在,则打开,否则创建同名文件进行操作,以同样的方法传入函数,输出内容到文件。 读取文件时,建议当前目录下无out.txt文件,这样运行时能直接看到文件的产生 文件内是否有内容也可以成为程序是否能跑通的标准。当出现编译器未指出,且程序有时能跑通,有时不行的问题时,ofs指向的文件不会产出数据。将ofs放在你觉得有问题的地方就行 完了
文件展示 $data.txt$ 3 3 N123;Object-Oriented Programming;Dave Smith;2009;3 1 A251;UML Modelling and Design;Barry Arthurs;2005;1 0 Z001;Practical Guide to STL;John Johnson;2000;5 2 12345;Joe Bloggs; 3 N123; A251; Z001; 20498;Alex Alexis;1 Z001; 19090;Mike Mike;2 N123; Z001;
$out.txt$ 记载了3本书 记载了3个借阅人 Book ID : N123 Title :Object-Oriented Programming Author :Dave Smith Year published :2009 Total number of copies :3 Number available for loan :0 Book ID : A251 Title :UML Modelling and Design Author :Barry Arthurs Year published :2005 Total number of copies :1 Number available for loan :0 Book ID : Z001 Title :Practical Guide to STL Author :John Johnson Year published :2000 Total number of copies :5 Number available for loan :0
实验代码 $Library.h$ #include <iostream> #include <string> #include <fstream> using namespace std;#ifndef LIBRARY_H #define LIBRARY_H class BookRecord { public : BookRecord (); BookRecord (string,string,string,string,int ,int ); void write (ifstream&) ; string id () ; string return_ID () ; void write_booknum () ; void write_bookloan () ; void check (ofstream&) ; void check () ; ~BookRecord (); private : string book_id; string book_title; string book_auther; string book_year; int book_total_num; int book_avail; }; class Borrower { public : Borrower (); Borrower (string,string,int ); void readbook (ifstream&) ; void write (ifstream&) ; string bookid (int ) ; int loan_bor () ; void return_id () ; void check () ; void createbook (int ) ; ~Borrower (); private : string borrower_id; string borrower; int loan; string *loan_books=nullptr ; }; class Catalogue { public : Catalogue (); void writebook (int & ) ; void writeloan (int & ) ; void create_record (ifstream&) ; void create_borrow (ifstream&) ; void find_record (BookRecord [],Borrower& ) ; void find_ID (BookRecord [],string) ; BookRecord* re_bookres () ; Borrower* re_borrow () ; ~Catalogue (); private : BookRecord *bookres=nullptr ; Borrower *bor=nullptr ; int book_total; int book_borrow; }; class Library { public : Library (int ,int ); Library (); void write_book (ifstream&,ofstream&) ; void write_loan (ifstream&,ofstream&) ; int & getbooks () ; int & getloan () ; void lookbook (int ) ; void lookborrow (int ) ; Catalogue& re_cltalogu () ; ~Library (); private : Catalogue cata; int loan; int books; }; #endif
$Library.cpp$ #include <iostream> #include <string> #include <fstream> #include "Library.h" using namespace std;BookRecord::BookRecord () { book_total_num=0 ; book_avail=0 ; }; BookRecord::BookRecord (string i, string t, string a, string y, int n, int l) : book_id (i), book_title (t), book_auther (a), book_year (y), book_total_num (n), book_avail (l){ if (book_id[0 ] < 65 || book_id[0 ] > 90 ) { cout << "书籍ID错误" << endl; exit (0 ); } if (book_year[0 ] < 49 || book_id[0 ] > 50 ) { cout << "出版时间错误" << endl; exit (0 ); } if (book_id.length () != 4 ) { cout << "书籍ID错误" << endl; exit (0 ); } }; BookRecord::~BookRecord (){}; void BookRecord::write (ifstream &ifs) { getline (ifs,book_id,';' ); if (book_id[1 ] < 65 || book_id[1 ] > 90 ) { cout << "书籍FID错误" << endl; exit (0 ); } if (book_id.length () != 5 ) { cout << "书籍LID错误" << endl; exit (0 ); } getline (ifs, book_title,';' ); getline (ifs, book_auther,';' ); getline (ifs,book_year,';' ); if (book_year[0 ] < 49 || book_id[0 ] > 50 ) { cout << "出版日期错错误" << endl; exit (0 ); } ifs >> book_total_num; ifs >> book_avail; } string BookRecord::id () { return book_id; } string BookRecord::return_ID () { return book_id; } void BookRecord::write_booknum () { book_avail--; if (book_avail < 0 ) { cout << "书库殆尽,无法借阅" << endl; book_avail = 0 ; } } void BookRecord::write_bookloan () { book_avail--; } void BookRecord::check (ofstream& ofs) { ofs << "Book ID :" << book_id << endl; ofs << "Title :" << book_title << endl; ofs << "Author :" << book_auther << endl; ofs << "Year published :" << book_year << endl; ofs << "Total number of copies :" << book_total_num << endl; ofs << "Number available for loan :" << book_avail << endl; } void BookRecord::check () { cout << "Book ID :" << book_id << endl; cout << "Title :" << book_title << endl; cout << "Author :" << book_auther << endl; cout << "Year published :" << book_year << endl; cout << "Total number of copies :" << book_total_num << endl; cout << "Number available for loan :" << book_avail << endl; } Borrower::Borrower () { loan=0 ; loan_books=nullptr ; }; Borrower::Borrower (string i, string b, int l) : borrower_id (i), borrower (b), loan (l) { if (borrower_id.length () != 5 ) { cout << "借阅人ID错误" << endl; exit (0 ); } }; void Borrower::readbook (ifstream& ifs) { for (int i = 0 ; i < loan; i++) { getline (ifs,loan_books[i],';' ); if (loan_books[i][1 ] < 65 || loan_books[i][1 ] > 90 ) { cout << "书籍ID错误" << endl; exit (0 ); } } } void Borrower::write (ifstream& ifs) { getline (ifs, borrower_id,';' ); if (borrower_id.length () != 6 ) { cout << "用户ID错误" << endl; exit (0 ); } getline (ifs, borrower,';' ); ifs >> loan; createbook (loan); readbook (ifs); } void Borrower::createbook (int a) { loan=a; this ->loan_books=new string[loan]; } string Borrower::bookid (int i) { if (i>loan-1 ) { cout<<i; exit (0 ); } else return loan_books[i]; } int Borrower::loan_bor () { return loan; } void Borrower::return_id () { for (int i = 0 ; i < loan; i++) { cout << loan_books[i] << " " ; } cout << endl; } void Borrower::check () { cout << "借阅人ID :" << borrower_id << endl; cout << "姓名 :" << borrower << endl; for (int i = 0 ; i < loan; i++) { cout << "第 " << i << " 个 :" ; cout << "借出书的数目 :" << loan_books[i] << endl; } } Borrower::~Borrower () { if (loan_books!=nullptr ) { delete [] loan_books; } }; Catalogue::Catalogue () { book_total = 0 ; book_borrow=0 ; bookres=nullptr ; bor=nullptr ; } void Catalogue::writebook (int & a) { book_total = a; } void Catalogue::writeloan (int & a) { book_borrow = a; } void Catalogue::create_record (ifstream &ifs) { bookres = new BookRecord[book_total]; for (int i = 0 ; i < book_total; i++) { bookres[i].write (ifs); } } void Catalogue::create_borrow (ifstream &ifs) { bor = new Borrower[book_borrow]; for (int i=0 ; i<book_borrow; i++) { bor[i].write (ifs); find_record (bookres, bor[i]); } } void Catalogue::find_record (BookRecord *a, Borrower &b) { int borrow_num = b.loan_bor (); for (int i = 0 ; i < book_total; i++) { for (int j = 0 ; j < borrow_num; j++) { string q1=a[i].id (); string q2=b.bookid (j); q2.erase (0 ,1 ); q1.erase (0 ,1 ); if (q1==q2) { a[i].write_booknum (); } } } } void Catalogue::find_ID (BookRecord a[], string id) { for (int i = 0 ; i < book_total; i++) { if (a[i].return_ID () == id) a[i].check (); } } BookRecord* Catalogue::re_bookres () { return bookres; } Borrower* Catalogue::re_borrow () { return bor; } Catalogue::~Catalogue () { if (bookres!=nullptr ) delete []bookres; if (bor!=nullptr ) delete []bor; } Library::Library (int a, int b) : books (a), loan (b){} Library::Library () { loan=0 ; books=0 ; }; void Library::write_book (ifstream &ifs,ofstream& ofs) { ifs >> books; ofs<<"记载了" <<books<<"本书" <<endl; }; void Library::write_loan (ifstream &ifs,ofstream& ofs) { ifs >> loan; ofs<<"记载了" <<loan<<"个借阅人" <<endl; }; int & Library::getbooks () { return books; } int & Library::getloan () { return loan; } void Library::lookbook (int a) { cata.re_bookres ()[a].check (); } void Library::lookborrow (int a) { cata.re_borrow ()[a].check (); } Catalogue& Library::re_cltalogu () { return cata; } Library::~Library (){};
$mian.cpp$ #include <iostream> #include <string> #include <fstream> #include "Library.h" #include "Library.cpp" using namespace std;int main () { Library library; ifstream ifs; ofstream ofs ("out.txt" ) ; ifs.open ("date.txt" , ios::in); if (!ofs.is_open ()) { cout<<"文件打开失败" <<endl; return 0 ; } if (ifs.is_open ()) { library.write_book (ifs,ofs); library.write_loan (ifs,ofs); library.re_cltalogu ().writebook (library.getbooks ()); library.re_cltalogu ().writeloan (library.getloan ()); library.re_cltalogu ().create_record (ifs); library.re_cltalogu ().create_borrow (ifs); for (int i=0 ;i<library.getbooks ();i++) library.re_cltalogu ().re_bookres ()[i].check (ofs); } ifs.close (); ofs.close (); return 0 ; }
实验心得与改进
ifs可以开在Library.cpp中,避免传入传出的繁琐。
ofs读取文件时存在问题,用”;“代替\n作为结束判断
Library类的内容不足,可以添加其他功能
可以改进Catalogue,将书籍索引改为数组直接访问,可以实现长期运营
动态数组的指针悬挂问题需要细心解决