《C++ 小程序编写系列》(第四部):实战:简易图书管理系统(类与对象篇)

《C++ 小程序编写系列》(第四部):实战:简易图书管理系统(类与对象篇)

在前三部中,我们从基础语法到结构体、vector 容器、文件操作,实现了计算器和学生成绩管理系统(面向过程编程)。本次第四部,我们将跨越到面向对象编程(OOP)的核心 ------类与对象,通过实现简易图书管理系统,掌握类的封装、构造函数、成员函数等关键知识点,完成从 "面向过程" 到 "面向对象" 的思维转变。

一、核心知识点预热(进阶版)

本次是 C++ 面向对象编程的入门关键,核心知识点如下:

  1. 类与对象 :类是自定义的抽象数据类型,封装了成员变量(数据)成员函数(行为);对象是类的实例化。
  2. 封装 :将成员变量私有化(private),仅通过公有(public)成员函数访问 / 修改,避免数据被直接篡改,提升代码安全性。
  3. 构造函数:与类名相同,无返回值,用于初始化对象的成员变量,简化对象创建流程。
  4. const 成员函数 :在成员函数后加const,保证函数不会修改成员变量,提升代码健壮性。
  5. 文件操作进阶:处理图书库存等数值型数据的持久化,兼容借阅 / 归还后的状态更新。

二、系统需求分析(精简核心功能)

我们实现的简易图书管理系统保留核心业务逻辑,兼顾面向对象特性:

  1. 添加图书:输入图书编号、书名、作者、库存数量,创建图书对象并存储。
  2. 查询图书:支持按图书编号(唯一)或书名(多结果)查询信息。
  3. 借阅图书:按编号找到图书,库存足够时减少库存,提示借阅成功。
  4. 归还图书:按编号找到图书,库存增加,提示归还成功。
  5. 显示所有图书:格式化输出所有图书的完整信息。
  6. 数据持久化:启动时加载文件中的图书数据,退出时保存数据。
  7. 退出系统:安全退出并自动保存数据。

三、完整代码实现(精简版)

cpp 复制代码
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <iomanip>
#include <algorithm>

using namespace std;

// 图书类:封装图书的属性和行为(面向对象核心)
class Book {
private:
    // 私有成员变量:仅能通过类内成员函数访问
    string bookId;    // 图书编号(唯一标识)
    string bookName;  // 书名
    string author;    // 作者
    int stock;        // 库存数量

public:
    // 构造函数:初始化图书对象(无参构造+带参构造)
    Book() = default; // 默认构造函数
    Book(string id, string name, string auth, int stk) 
        : bookId(id), bookName(name), author(auth), stock(stk) {}

    // 公有成员函数:提供对私有成员的访问和操作(封装的体现)
    string getBookId() const { return bookId; } // const:不修改成员变量
    string getBookName() const { return bookName; }
    string getAuthor() const { return author; }
    int getStock() const { return stock; }

    // 借阅图书:库存减1(返回是否成功)
    bool borrowBook() {
        if (stock > 0) {
            stock--;
            return true;
        }
        return false;
    }

    // 归还图书:库存加1
    void returnBook() {
        stock++;
    }

    // 设置图书信息(用于文件加载)
    void setInfo(string id, string name, string auth, int stk) {
        bookId = id;
        bookName = name;
        author = auth;
        stock = stk;
    }

    // 显示单本图书信息
    void showInfo() const {
        cout << left << setw(12) << bookId
             << setw(20) << bookName
             << setw(15) << author
             << setw(8) << stock << endl;
    }
};

// 函数声明(核心功能)
void loadBooks(vector<Book>& books); // 从文件加载图书数据
void saveBooks(const vector<Book>& books); // 保存图书数据到文件
void addBook(vector<Book>& books); // 添加图书
void queryBook(const vector<Book>& books); // 查询图书
void borrowBook(vector<Book>& books); // 借阅图书
void returnBook(vector<Book>& books); // 归还图书
void showAllBooks(const vector<Book>& books); // 显示所有图书
void showMenu(); // 显示菜单

int main() {
    vector<Book> books; // 用vector存储图书对象(类的实例集合)
    loadBooks(books); // 启动时加载数据

    int choice;
    while (true) {
        showMenu();
        cout << "请选择功能(1-7):";
        cin >> choice;
        cin.ignore(); // 忽略换行符

        switch (choice) {
            case 1: addBook(books); break;
            case 2: queryBook(books); break;
            case 3: borrowBook(books); break;
            case 4: returnBook(books); break;
            case 5: showAllBooks(books); break;
            case 6: saveBooks(books); cout << "数据已手动保存!" << endl; break;
            case 7: saveBooks(books); cout << "数据已保存,再见!" << endl; return 0;
            default: cout << "输入错误,请重新选择!" << endl;
        }

        cout << "\n按回车键继续...";
        cin.get();
        system("cls"); // Windows清屏,Linux/macOS用"clear"
    }

    return 0;
}

// 显示系统菜单
void showMenu() {
    cout << "========== 图书管理系统 ==========" << endl;
    cout << "1. 添加图书" << endl;
    cout << "2. 查询图书" << endl;
    cout << "3. 借阅图书" << endl;
    cout << "4. 归还图书" << endl;
    cout << "5. 显示所有图书" << endl;
    cout << "6. 手动保存数据" << endl;
    cout << "7. 退出系统" << endl;
    cout << "==================================" << endl;
}

// 从文件加载图书数据(books.txt)
void loadBooks(vector<Book>& books) {
    ifstream inFile("books.txt");
    if (!inFile.is_open()) {
        cout << "首次使用,暂无图书数据文件!" << endl;
        return;
    }

    string id, name, author;
    int stock;
    while (inFile >> id >> name >> author >> stock) {
        Book book;
        book.setInfo(id, name, author, stock);
        books.push_back(book);
    }
    inFile.close();
    cout << "成功加载" << books.size() << "本图书数据!" << endl;
}

// 保存图书数据到文件
void saveBooks(const vector<Book>& books) {
    ofstream outFile("books.txt");
    if (!outFile.is_open()) {
        cout << "文件打开失败,保存失败!" << endl;
        return;
    }

    for (const auto& book : books) {
        outFile << book.getBookId() << " "
                << book.getBookName() << " "
                << book.getAuthor() << " "
                << book.getStock() << endl;
    }
    outFile.close();
}

// 添加图书(检查编号唯一性)
void addBook(vector<Book>& books) {
    string id, name, author;
    int stock;

    cout << "----- 添加图书 -----" << endl;
    // 校验图书编号唯一性
    while (true) {
        cout << "请输入图书编号:";
        getline(cin, id);
        bool exist = false;
        for (const auto& book : books) {
            if (book.getBookId() == id) {
                exist = true;
                cout << "图书编号已存在,请重新输入!" << endl;
                break;
            }
        }
        if (!exist) break;
    }

    // 输入图书信息
    cout << "请输入图书名称:";
    getline(cin, name);
    cout << "请输入作者:";
    getline(cin, author);
    cout << "请输入库存数量:";
    cin >> stock;

    // 创建图书对象并添加到vector
    Book newBook(id, name, author, stock);
    books.push_back(newBook);
    cout << "图书添加成功!" << endl;
}

// 查询图书(按编号/书名)
void queryBook(const vector<Book>& books) {
    if (books.empty()) {
        cout << "暂无图书数据!" << endl;
        return;
    }

    int choice;
    cout << "----- 查询图书 -----" << endl;
    cout << "1. 按编号查询" << endl;
    cout << "2. 按书名查询" << endl;
    cout << "请选择查询方式:";
    cin >> choice;
    cin.ignore();

    if (choice == 1) {
        // 按编号查询(唯一)
        string id;
        cout << "请输入图书编号:";
        getline(cin, id);

        bool found = false;
        for (const auto& book : books) {
            if (book.getBookId() == id) {
                cout << "\n图书信息:" << endl;
                cout << "编号:" << book.getBookId() << "\t书名:" << book.getBookName() << endl;
                cout << "作者:" << book.getAuthor() << "\t库存:" << book.getStock() << endl;
                found = true;
                break;
            }
        }
        if (!found) cout << "未找到该图书!" << endl;
    } else if (choice == 2) {
        // 按书名查询(多结果)
        string name;
        cout << "请输入图书名称:";
        getline(cin, name);

        bool found = false;
        cout << "\n查询结果:" << endl;
        cout << left << setw(12) << "编号" << setw(20) << "书名" << setw(15) << "作者" << setw(8) << "库存" << endl;
        cout << "-----------------------------------------------------------" << endl;
        for (const auto& book : books) {
            if (book.getBookName().find(name) != string::npos) { // 模糊查询
                book.showInfo();
                found = true;
            }
        }
        if (!found) cout << "未找到相关图书!" << endl;
    } else {
        cout << "输入错误!" << endl;
    }
}

// 借阅图书
void borrowBook(vector<Book>& books) {
    if (books.empty()) {
        cout << "暂无图书数据!" << endl;
        return;
    }

    string id;
    cout << "----- 借阅图书 -----" << endl;
    cout << "请输入图书编号:";
    getline(cin, id);

    for (auto& book : books) { // 非const引用,可修改图书库存
        if (book.getBookId() == id) {
            if (book.borrowBook()) {
                cout << "借阅成功!当前库存:" << book.getStock() << endl;
            } else {
                cout << "库存不足,借阅失败!" << endl;
            }
            return;
        }
    }
    cout << "未找到该图书!" << endl;
}

// 归还图书
void returnBook(vector<Book>& books) {
    if (books.empty()) {
        cout << "暂无图书数据!" << endl;
        return;
    }

    string id;
    cout << "----- 归还图书 -----" << endl;
    cout << "请输入图书编号:";
    getline(cin, id);

    for (auto& book : books) {
        if (book.getBookId() == id) {
            book.returnBook();
            cout << "归还成功!当前库存:" << book.getStock() << endl;
            return;
        }
    }
    cout << "未找到该图书!" << endl;
}

// 显示所有图书信息
void showAllBooks(const vector<Book>& books) {
    if (books.empty()) {
        cout << "暂无图书数据!" << endl;
        return;
    }

    cout << "----- 所有图书信息 -----" << endl;
    cout << left << setw(12) << "编号" << setw(20) << "书名" << setw(15) << "作者" << setw(8) << "库存" << endl;
    cout << "-----------------------------------------------------------" << endl;
    for (const auto& book : books) {
        book.showInfo();
    }
}

四、代码解析(重点:面向对象思想)

1. 类的封装(Book 类)

这是本次代码的核心,体现了面向对象的封装性

  • 私有成员变量bookIdbookNameauthorstock被声明为private,外部无法直接访问或修改,避免了数据被恶意篡改(比如直接将库存改为负数)。
  • 公有成员函数 :提供了访问(getXXX)、修改(setInfo)和行为(borrowBookreturnBook)的接口,所有对私有数据的操作都通过这些函数完成,实现了 "数据隐藏"。

2. 构造函数

  • 我们定义了默认构造函数Book() = default;)和带参构造函数 ,用于初始化图书对象:
    • 带参构造函数通过初始化列表直接初始化成员变量,比在函数体内赋值更高效。
    • 默认构造函数用于文件加载时创建空对象,再通过setInfo方法赋值。

3. const 成员函数

  • getBookId() constshowInfo() const,函数后的const表示该函数不会修改类的任何成员变量,编译器会强制检查这一点,避免意外修改数据,提升代码的健壮性。

4. 类的实例化与存储

  • 我们用vector<Book> books存储多个图书对象(类的实例),vector 的动态特性与类的封装结合,既方便管理对象集合,又保证了数据安全。

5. 核心功能的面向对象实现

  • 借阅 / 归还图书 :直接调用图书对象的borrowBookreturnBook成员函数,将图书的行为封装在类内部,符合 "对象的行为由自身负责" 的面向对象思想(比如,图书自己知道如何处理借阅和归还,而不是在外部函数中直接修改库存)。

五、功能扩展思路

在本基础版本上,可进一步扩展功能,深化面向对象的学习:

  1. 添加图书分类 :在 Book 类中增加category成员变量,支持按分类查询图书。
  2. 借阅记录管理 :创建BorrowRecord类,记录借阅人、借阅时间、归还时间,关联 Book 类。
  3. 用户管理 :创建User类(管理员、普通用户),实现不同权限的操作(如管理员可添加图书,普通用户仅可借阅)。
  4. 图书排序 :重载<运算符,实现按书名、库存等条件排序图书。
  5. 异常处理:添加输入验证(如库存不能为负数),抛出并捕获异常,避免程序崩溃。

六、总结

本次我们通过简易图书管理系统,完成了从 "面向过程" 到 "面向对象" 的关键跨越,掌握了类的封装、构造函数、const 成员函数等核心知识点。面向对象编程是 C++ 的核心特性,它的封装、继承、多态三大特性将帮助我们编写更模块化、可维护、可扩展的代码。

与第三部的学生成绩管理系统(结构体 + 面向过程)相比,本次的类封装让代码的逻辑更清晰,数据更安全,更贴近实际项目的开发模式。下一部我们将继续深入,学习继承与多态,实现更复杂的面向对象程序。

相关推荐
浔川python社2 小时前
《C++ 小程序编写系列》(第五部):实战:多角色图书管理系统(继承与多态篇)
开发语言·c++
楠枬2 小时前
OpenFeign
java·spring cloud·微服务
CC.GG2 小时前
【Qt】信号和槽
开发语言·数据库·qt
是席木木啊2 小时前
基于MinIO Java SDK实现ZIP文件上传的方案与实践
java·开发语言
计算机毕设指导62 小时前
基于微信小程序的垃圾分类信息系统【源码文末联系】
java·spring boot·mysql·微信小程序·小程序·tomcat·maven
毕设源码-赖学姐2 小时前
【开题答辩全过程】以 高校就业系统的实现为例,包含答辩的问题和答案
java·eclipse
一起养小猫2 小时前
《Java数据结构与算法》第四篇(四):二叉树的高级操作查找与删除实现详解
java·开发语言·数据结构·算法
ALex_zry2 小时前
C++20/23标准对进程间共享信息的优化:从传统IPC到现代C++的演进
开发语言·c++·c++20
Coder_Boy_2 小时前
【人工智能应用技术】-基础实战-小程序应用(基于springAI+百度语音技术)智能语音控制-单片机交互代码
java·人工智能·后端·嵌入式硬件