手把手教你用 c++ 做 圖書管理系統

題目要求

1、問題描述 :
定義圖書類,屬性有:書名、出版社、ISBN 號、作者、庫存量、價格等信息和相關的 對屬性做操作的行爲。 主要完成對圖書的銷售、統計和圖書的簡單管理。
2、功能要求
(1)銷售功能:
購買書籍時,輸入相應的 ISBN 號,並在書庫中查找該書的相關信息。 如果有庫存量,輸入購買的冊數,進行相應計算。如果庫存量不夠,給出提示信息,結束購 買。
(2)圖書簡單管理功能:

添加功能:主要完成圖書信息的添加,要求 ISBN 號唯一。當添加了重複的編號時,則提示數據添加重複並取消添加。

查詢功能:可按書名、ISBN 號、作者、出版社進行查詢。若存在相應信息,輸出所查 詢的信息,若不存在該記錄,則提示“該標題不存在!”。

修改功能:可根據查詢結果對相應的記錄進行修改,修改時注意 ISBN 號的唯一性。

刪除功能:主要完成圖書信息的刪除。輸入要刪除的 ISBN 號,根據編號刪除該物品的 記錄,如果該編號不在物品庫中,則提示“該編號不存在”。

(3)統計功能。 輸出當前書庫中所有圖書的總數及詳細信息;可按書的價格、庫存量、作者、出版社進 行統計,輸出統計信息時,要按從大到小進行排序。

(4)圖書存盤:將當前程序中的圖書信息存入文件中。

(5)讀出信息:從文件中將圖書信息讀入程序。

思路分析

圖書管理系統肯定要定義“書”類啦~大概有這些屬性叭。
在這裏插入圖片描述
再分析功能要求,大概這個系統是這樣
在這裏插入圖片描述
大致將各個模塊分了出來,接下來就開始實現了!

各個模塊的實現

“書”類的創建

這個簡單,就這幾個屬性,直接上代碼

class Book
{
public:
    Book();
    ~Book();
    string name;
    int ISBN;
    int price;//價格
    string writer;//作者
    string publishingHouse;//出版社
    int inStock; //庫存
};

就把他放在Book.h 頭文件吧

管理模塊的創建及實現

管理權限

定義bool類函數來判斷用戶輸入的密碼是否正確,隨便寫一字符串就好

bool quanxian()
{
    cout << "請輸入密碼來證明您的權限" << endl;
    string c;
    cin >> c;
    return c == "73748156";
}

添加圖書

接下來是添加一本書,先聲明一個臨時的Book類型變量,然後依次讀入他的各個屬性,一定要注意判斷ISBN號是否唯一
先寫一個判斷ISBN號是否唯一的函數

int isExist(int isbn, vector<Book>& b)
{
    for (auto& i : b) { 
        //遍歷這個Book類vector,判斷ISBN是否唯一
        if (i.ISBN == isbn)return -1;
    }
    return 0;
}

然後寫添加書籍名稱的函數

void addBookName(vector<Book>& b, Book& c) {
    string name;
    cout << "請輸入書名" << endl;
    cin >> name;
    c.name = name;
}

添加ISBN的函數,在其中插入判斷ISBN是否唯一的函數

void addBookIsbn(vector<Book>& b, Book& c) {
    int isbn;
    cout << "請輸入ISBN號" << endl;
    while (true)
    {
        cin >> isbn;
        if (isExist(isbn, b) == -1)cout << "ISBN號重複,請重新輸入" << endl;
        else break;
    }
    c.ISBN = isbn;
}

添加作者的函數

void addBookWriter(vector<Book>& b, Book& c) {
    string writer;
    cout << "請輸入作者" << endl;
    cin >> writer;
    c.writer = writer;
}

添加出版社的函數

void addBookPublishingHouse(vector<Book>& b, Book& c) {
    string chubanshe;
    cout << "請輸入出版社" << endl;
    cin >> chubanshe;
    c.publishingHouse = chubanshe;
}

添加庫存的函數

void addBookInStock(vector<Book>& b, Book& c) {
    int kucun;
    cout << "請輸入庫存" << endl;
    cin >> kucun;
    c.inStock = kucun;
}

添加價格的函數

void addBookPrice(vector<Book>& b, Book& c) {
    int jiage;
    cout << "請輸入價格" << endl;
    cin >> jiage;
    c.price = jiage;
}

最後一起調用,做添加圖書的總函數

void addBook(vector<Book>& b) {
    Book newbook;//聲明一個Book類變量
    addBookName(b, newbook);
    addBookIsbn(b, newbook);
    addBookWriter(b, newbook);
    addBookPublishingHouse(b, newbook);
    addBookInStock(b, newbook);
    addBookPrice(b, newbook);
    //將信息讀取到newbook變量中
    b.push_back(newbook);
    //再將newbook添加到Book類vector中
    cout << "添加成功" << endl;
}

這樣就可以添加圖書了

查找圖書

查找圖書肯定要按多種條件查找
先做一個菜單

void showMenu4()
{
    cout << "*************************************" << endl;
    cout << "***   請選擇您檢索書籍的方式   *******" << endl;
    cout << "***   通過書名查找請按1        ******" << endl;
    cout << "***   通過IBSN號查找請按2      ******" << endl;
    cout << "***   通過作者查找請按3        ******" << endl;
    cout << "***   通過出版社查找請按4       ******" << endl;
    cout << "***   退出查找請按0           *******" << endl;
    cout << "***********************************" << endl;
}

理科生整的菜單沒有美感。。。。。。。

接下來需要考慮的問題是書籍信息重複問題
書名會重,一個作者會寫好多本書,出版社也肯定不會只出一本書
考慮到上述情況,查找結果可能不止一本書

故在查找函數內部再聲明一個Book類的vector,
將查到的書存在裏邊,然後再做第二次確認

還是先做查找書名的函數,參數傳兩個Book類的vector

void findBookName(vector<Book>& b, vector<Book>& c) {
    string name;
    cout << "請輸入您要查找的書籍名稱" << endl;
    cin >> name;
    for (auto& i : b) {
        if (i.name == name)
        {
            c.push_back(i);
        }
    }
}

然後是查找作者的函數

void findBookWriter(vector<Book>& b, vector<Book>& c) {
    string writer;
    cout << "請輸入您要查找的書籍作者" << endl;
    cin >> writer;
    for (auto& i : b) {
        if (i.writer == writer)
        {
            c.push_back(i);
        }
    }
}

還有查找出版社的函數

void findBookPublishingHouse(vector<Book>& b, vector<Book>& c) {
    string chubanshe;
    cout << "請輸入您要查找的書籍出版社" << endl;
    cin >> chubanshe;
    for (auto& i : b) {
        if (i.publishingHouse == chubanshe)
        {
            c.push_back(i);
        }
    }
}

最後是查找ISBN的函數,ISBN肯定是唯一的
所以這種檢索方式是最準確的
但是爲方便後續操作
依舊傳兩個vector

void findBookIsbn(vector<Book>& b, vector<Book>& c) {
    cout << "請輸入您要查找的書籍ISBN" << endl;
    int ISBN;
    cin >> ISBN;
    for (auto& i : b) {
        if (i.ISBN == ISBN)
        {
            c.push_back(i);
            Book::show(i);
        }
    }
}

查找之後肯定要把圖書信息顯示出來供使用者確認
做一個展示圖書信息的函數
我寫到了Book類裏

void Book::show(Book b) {
    cout << "書名:" << b.name 
    	 << "\tISBN:" << b.ISBN 
    	 << "\t作者:"<< b.writer 
 	     << "\t出版社:" << b.publishingHouse 
 	     << "\t價格:" << b.price 
  	     << "\t庫存:" << b.inStock << endl;
}

最後把這幾個查找函數用一個函數封裝到一起

Book findBook(vector<Book>& b)
{
    Book tmp;
    vector<Book>c;//爲防止書籍其他信息重複,將信息重複的查找結果存在c中
    tmp.ISBN = 0;
    showMenu4();
    char choose2;
    cin >> choose2;
    switch (choose2)
    {

    case '1'://按書名查找
    {
        findBookName(b, c);
        break;
    }
    case '2'://ISBN
    {
        findBookIsbn(b, c);
        break;
    }
    case '3'://作者
    {
        findBookWriter(b, c);
        break;
    }
    case '4'://出版社
    {
        findBookPublishingHouse(b, c);
        break;
    }
    case '0'://退出
    {
        cout << "歡迎下次使用" << endl;
        tmp.ISBN = -1;
        break;
    }
    default: {
        cout << "指令錯誤,請重新輸入" << endl;
        break;
    }
    }
    //開始二次檢索
    if (tmp.ISBN != -1)
    {
        if (c.empty())
        //判斷找沒找到,沒找到vector就是空的
        {
            cout << "查無此書" << endl;
            tmp.ISBN = -1;
        }
        else if (c.size() == 1)return c[0];
        //如果vector內只有一個函數,就不再遍歷浪費時間啦
        else
        {
            cout << "請確認您要查找的書籍" << endl;
            int i;
            for (i = 0; i < c.size(); ++i) {
            //c裏不止一本書,遍歷c確認查找的書
                cout << i + 1 << "、\t";
                Book::show(c[i]);
            }
            cout << "請選擇您要查找的書籍序號" << endl;
            cin >> i;
            return c[i - 1];
        }
    }
    return tmp;
}

完事,下一個

修改圖書

修改圖書也簡單,跟添加圖書差不多吧
無非就是修改單個信息
肯定是要先找到圖書,再去修改,
所以函數中傳一個vector和一本書就好

先做一個菜單

void showMenu5()
{
    cout << "*************************************" << endl;
    cout << "*****   您想要修改該書哪種信息   ******" << endl;
    cout << "*******    修改書名請按1      *******" << endl;
    cout << "*******    修改ISBN請按2      *******" << endl;
    cout << "*******    修改作者請按3      *******" << endl;
    cout << "*******   修改出版社請按4     *******" << endl;
    cout << "*******    修改價格請按5      *******" << endl;
    cout << "*******    修改庫存請按6      *******" << endl;
    cout << "*******    退出修改請按0      *******" << endl;
    cout << "***********************************" << endl;
}

理科生審美標配菜單~

然後還是先做修改單個信息的函數
修改書名的

void modifyBookName(vector<Book>& b, Book& c)
{
    string name;
    cout << "請輸入修改後書名" << endl;
    cin >> name;
    int i = 0;
    for (; i < b.size(); ++i) {
        if (b[i].ISBN == c.ISBN)break;
    }
    b[i].name = name;
    cout << "修改成功" << endl;
}

修改ISBN的
這裏注意修改後的ISBN不能重複,
調用一次之前寫好的函數來判斷ISBN是否唯一

void modifyBookIsbn(vector<Book>& b, Book& c)
{
    int isbn;
    cout << "請輸入修改後ISBN號" << endl;
    cin >> isbn;
    if (isExist(isbn, b) == -1)//判斷ISBN是否重複
    {
        cout << "ISBN重複,修改失敗" << endl;
    }
    else {
        int i = 0;
        for (; i < b.size(); ++i) {
            if (b[i].ISBN == c.ISBN)break;
        }
        b[i].ISBN = isbn;
        cout << "修改成功" << endl;
    }
}

修改作者的

void modifyBookWriter(vector<Book>& b, Book& c)
{
    string zuozhe;
    cout << "請輸入修改後作者" << endl;
    cin >> zuozhe;
    int i = 0;
    for (; i < b.size(); ++i) {
        if (b[i].ISBN == c.ISBN)break;
    }
    b[i].writer = zuozhe;
    cout << "修改成功" << endl;
}

修改出版社的

void modifyBookChubanshe(vector<Book>& b, Book& c)
{
    string chubanshe;
    cout << "請輸入修改後出版社" << endl;
    cin >> chubanshe;
    int i = 0;
    for (; i < b.size(); ++i) {
        if (b[i].ISBN == c.ISBN)break;
    }
    b[i].publishingHouse = chubanshe;
    cout << "修改成功" << endl;
}

修改庫存的

void modifyBookKucun(vector<Book>& b, Book& c)
{
    int kucun;
    cout << "請輸入修改後庫存" << endl;
    cin >> kucun;
    int i = 0;
    for (; i < b.size(); ++i) {
        if (b[i].ISBN == c.ISBN)break;
    }
    b[i].inStock = kucun;
    cout << "修改成功" << endl;
}

修改價格的

void modifyBookJiage(vector<Book>& b, Book& c)
{
    int jiage;
    cout << "請輸入修改後價格" << endl;
    cin >> jiage;
    int i = 0;
    for (; i < b.size(); ++i) {
        if (b[i].ISBN == c.ISBN)break;
    }
    b[i].price = jiage;
    cout << "修改成功" << endl;
}

最後封裝到一起

void modifyBookInformation(vector<Book>& b, Book& c)
{
    while (true)
    {
        showMenu5();
        char choose5;
        cin >> choose5;
        switch (choose5) {
        case '1':
        {
            modifyBookName(b, c);
            break;
        }
        case '2': {
            modifyBookIsbn(b, c);
            break;
        }
        case '3': {
            modifyBookWriter(b, c);
            break;
        }
        case '4': {
            modifyBookChubanshe(b, c);
            break;
        }
        case '5': {
            modifyBookJiage(b, c);
            break;
        }
        case '6':
        {
            modifyBookKucun(b, c);
            break;
        }
        case '0':
        {
            cout << "退出修改系統" << endl;
            return;
        }
        default:
        {
            cout << "指令錯誤,請重新輸入" << endl;
            break;
        }
        }

    }
}

刪除圖書

這個更簡單了,因爲是用的vector來存儲書籍
所以刪除圖書用vector中的erase方法就行

同樣也是先查找書籍再刪除
參數傳一個vector和一本書

我把這個函數寫到了Book類中

void Book::deleteBook(vector<Book>& b, Book c)
{
    int i;
    for (i = 0; i < b.size(); i++) {//通過ISBN查找這本書
        if (b[i].ISBN == c.ISBN) {
            b.erase(b.begin() + i);//刪除這本書
        }
    }
    cout << "刪除成功" << endl;
}

已經完成一半多啦!
在這裏插入圖片描述

銷售模塊的創建與實現

銷售圖書無非就是先檢索出來
判斷庫存,然後輸出

直接上代碼

void buyBook(vector<Book>& b) {
    Book mai = findBook(b);
    if (mai.ISBN != -1)
    {
        int number;
        cout << "請輸入要購買的數量" << endl;
        cin >> number;
        if (number > mai.inStock)//判斷庫存夠不夠
        {
            cout << "庫存不足,購買失敗" << endl;
        }
        else
        {
            int huaxiao = number * mai.price;
            for (int i = 0; i < b.size(); ++i) {
                //遍歷找到這本書,並調整他的庫存
                if (b[i].ISBN == mai.ISBN)
                {
                    b[i].inStock -= number;
                    break;
                }
            }
            cout << "購買成功" << endl;
            cout << "共花費 " << huaxiao << " 元" << endl;
        }
    }
}

統計模塊的創建與實現

統計也就是按ISBN,庫存或價格排序輸出下,
還是先做個菜單

void showMenu6() {
    cout << "*********************************************" << endl;
    cout << "******    選擇你要統計圖書信息的排序方式    ******" << endl;
    cout << "*******        按ISBN統計請按1         *******" << endl;
    cout << "*******        按庫存統計請按2          *******" << endl;
    cout << "*******        按價格統計請按3          *******" << endl;
    cout << "*******          退出請按0             *******" << endl;
    cout << "*********************************************" << endl;
}

簡潔且美觀!

因爲是用vector存儲的書籍
所以排序也是很容易操作
直接用sort方法就可以
故只需要自己定義比較函數

先定義比較ISBN的比較函數

bool isbnCmp(const Book& a, const Book& b)
{
    return a.ISBN > b.ISBN;
}

接着是庫存比較函數

bool inStockCmp(const Book& a, const Book& b)
{
    if (a.inStock == b.inStock)return a.ISBN > b.ISBN;
    //庫存相等的時候按ISBN排序
    return a.inStock > b.inStock;
}

然後是價格比較函數

bool priceCmp(const Book& a, const Book& b)
{
    if (a.price == b.price)return a.ISBN > b.ISBN;
    //價格相等的時候按ISBN排序
    return a.price > b.price;
}

最後封裝好統計函數

void tongji(vector<Book>& b)
{
    showMenu6();
    char choose6;
    cin >> choose6;
    switch (choose6)
    {
    case '0'://退出
    {
        cout << "退出統計系統" << endl;
        return;
    }
    case '1'://isbn
    {
        sort(b.begin(), b.end(), isbnCmp);//排序
        for (const auto& i : b)
        {
            Book::show(i);//顯示排完序後的書庫
        }
        break;
    }
    case '2'://庫存
    {
        sort(b.begin(), b.end(), inStockCmp);
        for (const auto& i : b)
        {
            Book::show(i);
        }
        break;
    }
    case '3'://價格
    {
        sort(b.begin(), b.end(), priceCmp);
        for (const auto& i : b)
        {
            Book::show(i);
        }
        break;
    }
    }
}

文件的讀取與存儲

用文件流寫入或讀取文件
記得要加 ftream 的頭文件
並且加上宏定義#define FILENAME "library.txt"

open函數要寫打開模式

寫入模式 ios::out
讀取模式 ios::in

具體操作方法如下
保存Book類vector信息代碼

void save(vector<Book>& b)
{
    ofstream ofs;
    ofs.open(FILENAME, ios::out);
    for (auto& i : b) {//錄入每本書信息
        ofs << i.name << " " << i.ISBN << " " << i.writer << " "
            << i.publishingHouse << " " 
            << i.inStock << " " << i.price << endl;
        //將所有信息存儲,信息之間以空格分隔,書之間以換行符分隔
    }
    cout << "保存成功" << endl;
    ofs.close();//關閉文件

}

還有將文件內容讀取到Book類vector中
方法是先聲明一個Book變量,讀取信息後將其插入vector中
代碼如下

void fetchBook(vector<Book>& b)
{
    ifstream ifs;
    ifs.open(FILENAME, ios::in);//讀文件
    if (!ifs.is_open())//判斷是否存在
    {
        cout << "圖書文件不存在" << endl;
        ifs.close();
        return;
    }

    Book temp;
    while (ifs >> temp.name && ifs >> temp.ISBN && ifs 
    	>> temp.writer && ifs >> temp.publishingHouse &&
        ifs >> temp.inStock && ifs >> temp.price)//信息讀取到temp中
    {
        b.push_back(temp);//將temp存在b中
    }
    ifs.close();
    if (b.empty())
    {
        cout << "圖書文件爲空" << endl;
    }
    else
        cout << "當前圖書種類數目爲" << b.size() << "本" << endl;
}

完成!
到這裏,題目要求的幾個模塊就都完成啦~
順手拓展下再加個用戶登錄界面完善下吧

創建簡易登錄界面

有登錄肯定得有註冊
還是老樣子
先做一個巨好看的菜單

void showMenu0() {
    cout << "*************************************" << endl;
    cout << "********  書是人類進步的階梯  *********" << endl;
    cout << "********    登錄帳號請按1    *********" << endl;
    cout << "********    註冊賬號請按2    *********" << endl;
    cout << "********  退出圖書系統請按0  *********" << endl;
    cout << "*************************************" << endl;
}

好看!
在這裏插入圖片描述

接着先寫一個類,就叫User叭

class User {
public:
    User() {}
    ~User() {}
    string userName;
    string password;
};

然後開始寫註冊函數
當然也要判斷用戶名是否唯一

判斷用戶名是否唯一的函數代碼

int isUserExist(string name, vector<User>u) {
    for (int i = 0; i < u.size(); ++i) {
        if (u[i].userName == name) return i;
    }
    return -1;
}

接着是註冊函數的實現,跟添加圖書差不多,
還是先聲明一個User類變量,輸入各信息後再將其插入到vector中

既然是存儲用戶信息的vector,當然也要保存在文件中
同樣加一個宏定義#define FILENAME2 "users.txt"

然後上代碼

void zhuce(vector<User>& u)
{
    string password;
    User tmp;
    string name;
    cout << "請輸入用戶名" << endl;
    cin >> name;
    int a = isUserExist(name, u);
    if (a == -1)
    {
        tmp.userName = name;
        cout << "請輸入密碼" << endl;
        cin >> password;
        tmp.password = password;
        u.push_back(tmp);
        ofstream ofs;
        ofs.open(FILENAME2, ios::out);
        for (auto& i : u) {//錄入用戶信息
            ofs  << i.userName << " "<< i.password << endl;
        }
        cout << "保存成功" << endl;
        ofs.close();//關閉文件
    }
    else cout << "該用戶名已被使用,註冊失敗" << endl;
}

當然不能忘了還有登錄的代碼沒寫

bool denglu(vector<User> u)
{
    string name, password;
    cout << "請輸入用戶名" << endl;
    cin >> name;
    int a = isUserExist(name, u);
    if (a == -1) {
        cout << "用戶名不存在,登錄失敗" << endl;
        return false;
    }
    else
    {
        cout << "請輸入密碼" << endl;
        cin >> password;
        if (u[a].password == password) {
            cout << "登錄成功" << endl;
            return true;
        }
        else
        {
            cout << "密碼錯誤,登錄失敗" << endl;
            return false;
        }
    }
}

再補一下主函數的封裝
在這裏插入圖片描述

主函數的封裝

主函數中聲明兩個 vector ,再調用兩個函數讀取本地文件到 vector 中
之後調用 選擇函數,來封裝所有的模塊

int main() {
    vector<Book>lib;
    vector<User>users;
    fetchUser(users);
    fetchBook(lib);
    selectOption(lib, users);
    return 0;
}

主菜單選項的封裝

還是先做一個百看不膩的美麗菜單

void showMenu1()
{
    cout << "*************************************" << endl;
    cout << "********  書是人類進步的階梯  *********" << endl;
    cout << "********    購買書籍請按1    *********" << endl;
    cout << "********    整理書籍請按2    *********" << endl;
    cout << "********  顯示書籍信息請按3  *********" << endl;
    cout << "********  保存圖書信息請按4  *********" << endl;
    cout << "********  退出圖書系統請按0  *********" << endl;
    cout << "*************************************" << endl;
}

覺得好看可以多看一會,我不會不好意思的
在這裏插入圖片描述
接着是 選擇函數,就把所有模塊扔到一個 switch 結構裏就好啦 ~


```cpp
void selectOption(vector<Book>& b, vector<User>& u)
{
    int h = 0;
    char choose0;
    do {
        showMenu0();
        cin >> choose0;
        switch (choose0)
        {
        case'1'://登錄
            if (denglu(u))
            {
                h = 1;
                break;
            }
            else
                continue;
        case'2'://註冊
            zhuce(u);
            break;
        case'0':
            cout << "歡迎下次使用" << endl;
            return;
        }
        system("pause");
        system("cls");
    } while ((choose0 != '0' && h != 1));
    while (true)
    {
        //展示主菜單
        showMenu1();
        char choose;
        cin >> choose;
        switch (choose)
        {
        case'1'://購買
        {
            buyBook(b);
            break;
        }
        case'2'://整理
        {
            if (quanxian())
                arrangeBook(b);
            else cout << "密碼錯誤,您沒有權限" << endl;
            break;
        }
        case '3'://統計
        {
            if (b.empty())
            {
                cout << "當前無圖書" << endl;
                break;
            }
            tongji(b);
            break;
        }
        case '4'://保存
        {
            save(b);
            break;
        }
        case'0'://退出
        {
            cout << "歡迎下次使用" << endl;
            return;
        }
        default:
        {
            cout << "指令錯誤,請重新輸入" << endl;
        }
        }
        system("pause");
        system("cls");
    }
}

在這裏插入圖片描述
成品上傳在這裏了

燕大的朋友們可以私信管我要代碼哦
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章