7、C++项目实战:图书管理系统(面向对象基础)
说实话,很多初学者学完C++语法后,最迷茫的就是——这些东西到底怎么串起来用?
我个人习惯是,每学完一个阶段,就做一个完整的小项目。图书管理系统,就是面向对象入门最经典的实战项目。它不复杂,但足够让你把类、对象、封装、继承、多态这些概念真正落地。
7.1 项目需求分析
先别急着写代码。我见过太多人上来就敲键盘,结果写到一半发现结构乱了。
这个系统要做什么?说白了就三件事:
- 管理图书信息:书名、作者、ISBN、是否借出
- 管理读者信息:姓名、编号、已借图书列表
- 处理借还操作:借书、还书、查询
嗯,就这么简单。但我们要用面向对象的方式去设计它。
核心思路:把现实世界中的"书"和"读者"抽象成类,把操作封装在类的方法里。
7.2 类的设计
我一般先画一个简单的类图,理清楚关系再动手。这里我直接用SVG画给你看:
你看,三个类之间的关系很清晰:Library 管理 Book 和 Reader,Reader 关联 Book(借阅关系)。
7.3 代码实现
好,我们开始写代码。先从 Book 类开始:
// Book.h
#pragma once
#include <string>
using namespace std;
class Book {
private:
string title;
string author;
string isbn;
bool isBorrowed;
public:
Book(string t, string a, string i)
: title(t), author(a), isbn(i), isBorrowed(false) {}
string getTitle() const { return title; }
string getIsbn() const { return isbn; }
bool getStatus() const { return isBorrowed; }
void borrow() {
if (isBorrowed) {
cout << "这本书已被借出!" << endl;
return;
}
isBorrowed = true;
cout << "借书成功:" << title << endl;
}
void returnBook() {
if (!isBorrowed) {
cout << "这本书没有被借出!" << endl;
return;
}
isBorrowed = false;
cout << "还书成功:" << title << endl;
}
};
小技巧:构造函数用初始化列表,比在函数体内赋值效率更高。我早期写代码时没注意这个,后来被同事review指出来才改的。
接下来是 Reader 类:
// Reader.h
#pragma once
#include <vector>
#include <algorithm>
#include "Book.h"
class Reader {
private:
string name;
string id;
vector<Book*> borrowedBooks; // 存指针,避免拷贝
public:
Reader(string n, string i) : name(n), id(i) {}
void borrowBook(Book* book) {
if (borrowedBooks.size() >= 5) {
cout << "每人最多借5本书!" << endl;
return;
}
book->borrow();
borrowedBooks.push_back(book);
}
void returnBook(Book* book) {
auto it = find(borrowedBooks.begin(), borrowedBooks.end(), book);
if (it != borrowedBooks.end()) {
book->returnBook();
borrowedBooks.erase(it);
} else {
cout << "你没有借这本书!" << endl;
}
}
void showBorrowed() const {
cout << name << " 已借图书:" << endl;
for (auto book : borrowedBooks) {
cout << " - " << book->getTitle() << endl;
}
}
};
嗯,这里有个细节:borrowedBooks 存的是指针。为什么?因为 Book 对象由 Library 统一管理,读者只是"引用"它,不负责销毁。如果存对象副本,改状态就不同步了。
注意:用指针就要小心悬空指针。我这里假设 Library 的生命周期比 Reader 长,实际项目中建议用 shared_ptr。
最后是 Library 类,负责统筹管理:
// Library.h
#pragma once
#include <vector>
#include <algorithm>
#include "Book.h"
#include "Reader.h"
class Library {
private:
vector<Book> books;
vector<Reader> readers;
public:
void addBook(const string& title, const string& author, const string& isbn) {
books.emplace_back(title, author, isbn);
}
void addReader(const string& name, const string& id) {
readers.emplace_back(name, id);
}
Book* findBook(const string& isbn) {
for (auto& book : books) {
if (book.getIsbn() == isbn) {
return &book;
}
}
return nullptr;
}
Reader* findReader(const string& id) {
for (auto& reader : readers) {
if (reader.getId() == id) {
return &reader;
}
}
return nullptr;
}
void borrowBook(const string& readerId, const string& isbn) {
Reader* reader = findReader(readerId);
Book* book = findBook(isbn);
if (!reader || !book) {
cout << "读者或图书不存在!" << endl;
return;
}
reader->borrowBook(book);
}
void returnBook(const string& readerId, const string& isbn) {
Reader* reader = findReader(readerId);
Book* book = findBook(isbn);
if (!reader || !book) {
cout << "读者或图书不存在!" << endl;
return;
}
reader->returnBook(book);
}
};
7.4 主函数测试
写完了,跑一下看看效果:
int main() {
Library lib;
// 添加图书
lib.addBook("C++ Primer", "Lippman", "978-7-111-1");
lib.addBook("Effective C++", "Meyers", "978-7-111-2");
// 添加读者
lib.addReader("张三", "R001");
lib.addReader("李四", "R002");
// 借书
lib.borrowBook("R001", "978-7-111-1");
lib.borrowBook("R001", "978-7-111-2");
// 还书
lib.returnBook("R001", "978-7-111-1");
return 0;
}
输出结果:
借书成功:C++ Primer
借书成功:Effective C++
还书成功:C++ Primer
7.5 避坑指南
我曾经在项目里犯过一个低级错误——vector 存对象时,忘记考虑对象拷贝带来的副作用。比如 Library::addBook 里用 emplace_back,如果 Book 类里有指针成员,浅拷贝就会出问题。好在这个项目里 Book 只有 string 和 bool,没问题。
另外,你想想看,如果读者借书时直接修改 Book 的 isBorrowed,而 Reader 里又存了一份副本,那状态就乱套了。所以我才用指针统一管理。
7.6 扩展思考
这个系统还能怎么改进?
- 加上文件读写,让数据持久化
- 用
map代替vector查找,效率更高 - 引入继承,比如
StudentReader和TeacherReader有不同的借书上限
嗯,这些就留给你自己去尝试了。面向对象的核心就是——把数据和操作绑在一起,让代码更贴近现实逻辑。
总结一句话:图书管理系统虽小,但封装、关联、生命周期管理这些概念全用上了。做完这个,你对面向对象的理解会上一个台阶。
公众号:蓝海资料掘金营,微信deep3321