跳到主要内容
C++ 图书管理系统:面向对象、STL 与数据持久化 | 极客日志
C++ 算法
C++ 图书管理系统:面向对象、STL 与数据持久化 综述由AI生成 一个基于 C++ 面向对象思想开发的图书管理系统。系统采用 STL 容器(vector/map)进行数据存储,无需外部数据库,通过文件实现数据持久化。核心功能包括图书与读者的增删改查、借阅归还流程闭环、以及运营数据统计。设计上运用了封装、继承和多态特性,定义了 Book、Reader 及其派生类,并通过 LibrarySystem 类统一管理业务逻辑。代码包含完整的控制台交互逻辑、输入校验及文件 IO 处理,适合 C++ 课程实训参考。
花里胡哨 发布于 2026/3/22 更新于 2026/6/5 701 浏览项目介绍
本图书管理系统基于 C++ 面向对象编程思想开发,是一套轻量化、无数据库依赖的控制台端图书馆运营管理解决方案。系统核心功能覆盖图书全生命周期管理、读者分级管控、借阅归还流程闭环、数据持久化存储及运营数据统计五大维度。
图书分类管理 :支持小说、教材两类图书的精细化管理,可完成图书信息的新增、查询、修改、删除操作,内置'已借出图书禁止删除'的业务校验规则。
读者分级管控 :采用学生、教师双维度读者体系设计,自动适配差异化借阅上限(学生 3 本/教师 5 本)。
借阅归还闭环 :构建多维度校验机制,借阅成功自动生成带日期戳的借阅记录,归还操作同步更新状态。
数据持久化 :基于文本文件实现数据本地存储,系统启动自动加载历史数据,退出时完成数据备份。
统计分析 :内置报表生成功能,实时统计总图书量、已借出图书量等核心运营数据。
核心技术栈
技术点 应用场景 面向对象(OOP) 图书/读者类的封装、继承、多态 STL 容器(vector/map) 数据存储(vector 遍历、map 快速查找) 文件 IO 流 文本文件实现数据持久化 字符串处理 CSV 格式数据解析、分割 动态类型转换(dynamic_cast) 派生类对象的类型判断 控制台交互优化 输入校验、清屏、暂停等
项目结构
代码按'头文件 + 实现文件'分离规范组织,目录结构如下:
Library Management System/
├─ Book.h
├─ Book.cpp
├─ Reader.h
├─ Reader.cpp
├─ BorrowRecord.h
├─ BorrowRecord.cpp
├─ LibrarySystem.h
├─ LibrarySystem.cpp
├─ Utils.h
├─ Utils.cpp
├─ main.cpp
└─ data /
核心功能模块详解
类的设计
本系统通过基类抽象共性、派生类扩展特性 ,结合纯虚函数实现多态,是面向对象思想的核心体现。
图书类:基类 Book + 派生类 NovelBook/TextBook
功能说明 :封装所有图书的通用属性(编号、名称、作者、借阅状态),派生类扩展特有属性(小说类型、教材适用年级),通过纯虚函数 showInfo() 实现多态展示。
#pragma once
#include "Utils.h"
class Book {
public :
Book (const string& bookId, const string& bookName, const string& author, bool isBorrow);
virtual void showInfo () = 0 ;
void setBookName (const string& bookName) ;
void setAuthor (const string& author) ;
void setIsBorrowed (bool key) ;
string getBookId () const ;
string getBookName () const ;
string getAuthor () const ;
bool getIsBorrowed () const ;
~Book ();
private :
string bookId;
string bookName;
string author;
bool isBorrowed;
};
class NovelBook : public Book {
public :
NovelBook (const string& bookId, const string& bookName, const string& author, bool isBorrow, const string& novelType);
void showInfo () override ;
string getNovelType () const ;
private :
string novelType;
};
class TextBook : public Book {
public :
TextBook (const string& bookId, const string& bookName, const string& author, bool isBorrow, const string& grade);
void showInfo () override ;
string getGrade () const ;
private :
string grade;
};
#include "Book.h"
Book::Book (const string& bookId, const string& bookName, const string& author, bool isBorrow) {
this ->bookId = bookId;
this ->bookName = bookName;
this ->author = author;
this ->isBorrowed = isBorrow;
}
NovelBook::NovelBook (const string& bookId, const string& bookName, const string& author, bool isBorrowed, const string& novelType)
: Book (bookId, bookName, author, isBorrowed), novelType (novelType) {}
void NovelBook::showInfo () {
cout << "编号:" << getBookId () << endl;
cout << "书名:" << getBookName () << endl;
cout << "作者:" << getAuthor () << endl;
if (getIsBorrowed ()) cout << "借阅状态:已借出" << endl;
else cout << "借阅状态:未借出" << endl;
cout << "小说类型:" << novelType << endl;
}
TextBook::TextBook (const string& bookId, const string& bookName, const string& author, bool isBorrowed, const string& grade)
: Book (bookId, bookName, author, isBorrowed), grade (grade) {}
void TextBook::showInfo () {
cout << "编号:" << getBookId () << endl;
cout << "书名:" << getBookName () << endl;
cout << "作者:" << getAuthor () << endl;
if (getIsBorrowed ()) cout << "借阅状态:已借出" << endl;
else cout << "借阅状态:未借出" << endl;
cout << "教材适用年级:" << grade << endl;
}
void Book::setBookName (const string& bookName) { this ->bookName = bookName; }
void Book::setAuthor (const string& author) { this ->author = author; }
void Book::setIsBorrowed (bool key) { this ->isBorrowed = key; }
string Book::getBookId () const { return bookId; }
string Book::getBookName () const { return bookName; }
string Book::getAuthor () const { return author; }
bool Book::getIsBorrowed () const { return isBorrowed; }
Book::~Book () {}
string NovelBook::getNovelType () const { return novelType; }
string TextBook::getGrade () const { return grade; }
基类 Book 用 纯虚函数 showInfo() 抽象'展示图书信息'的行为,派生类必须重写;
调用 showInfo() 时,会自动匹配对象的实际类型(小说/教材),实现多态 ;
所有属性私有化,通过 set/get 方法访问,体现封装性 。
读者类:基类 Reader + 派生类 StudentReader/TeacherReader 功能说明 :封装读者通用属性(编号、姓名、已借阅数),派生类扩展特有属性(学号/教师工号),通过 borrowLimit() 实现不同读者的借阅上限(学生 3 本、教师 5 本)。
#pragma once
#include "Utils.h"
class Reader {
public :
Reader (const string& readerId, const string& name, int borrowCount);
virtual int borrowLimit () = 0 ;
virtual void showInfo () = 0 ;
void setName (const string& name) ;
void BorrowCountAdd () ;
void BorrowCountSub () ;
string getReaderId () const ;
string getName () const ;
int getBorrowCount () const ;
~Reader ();
private :
string readerId;
string name;
int borrowCount;
};
class StudentReader : public Reader {
public :
StudentReader (const string& readerId, const string& name, int borrowCount, const string& studentId);
int borrowLimit () override ;
void showInfo () override ;
string getStudentId () const ;
private :
string studentId;
};
class TeacherReader : public Reader {
public :
TeacherReader (const string& readerId, const string& name, int borrowCount, const string& teacherId);
int borrowLimit () override ;
void showInfo () override ;
string getTeacherId () const ;
private :
string teacherId;
};
#include "Reader.h"
Reader::Reader (const string& readerId, const string& name, int borrowCount) {
this ->readerId = readerId;
this ->name = name;
this ->borrowCount = borrowCount;
}
void Reader::setName (const string& name) { this ->name = name; }
void Reader::BorrowCountAdd () { borrowCount++; }
void Reader::BorrowCountSub () { borrowCount--; }
string Reader::getReaderId () const { return readerId; }
string Reader::getName () const { return name; }
int Reader::getBorrowCount () const { return borrowCount; }
Reader::~Reader () {}
StudentReader::StudentReader (const string& readerId, const string& name, int borrowCount, const string& studentId)
: Reader (readerId, name, borrowCount), studentId (studentId) {}
int StudentReader::borrowLimit () { return 3 ; }
void StudentReader::showInfo () {
cout << "读者编号:" << getReaderId () << endl;
cout << "姓名:" << getName () << endl;
cout << "类型:学生" << endl;
cout << "学号:" << studentId << endl;
cout << "已借阅数量:" << getBorrowCount () << "/3" << endl;
}
string StudentReader::getStudentId () const { return studentId; }
TeacherReader::TeacherReader (const string& readerId, const string& name, int borrowCount, const string& teacherId)
: Reader (readerId, name, borrowCount), teacherId (teacherId) {}
int TeacherReader::borrowLimit () { return 5 ; }
void TeacherReader::showInfo () {
cout << "读者编号:" << getReaderId () << endl;
cout << "姓名:" << getName () << endl;
cout << "类型:教师" << endl;
cout << "工号:" << teacherId << endl;
cout << "已借阅数量:" << getBorrowCount () << "/5" << endl;
}
string TeacherReader::getTeacherId () const { return teacherId; }
借阅记录类 BorrowRecord 功能说明 :记录图书借阅的核心信息(图书编号、读者编号、借阅日期、归还日期),支持'未归还'状态的标记。
#pragma once
#include "Utils.h"
class BorrowRecord {
public :
BorrowRecord (const string &bookId, const string &readerId, const string &borrowDate);
BorrowRecord (const string &bookId, const string &readerId, const string &borrowDate, const string &returnDate);
void setReturnDate (string returnDate) ;
string getBookId () const ;
string getReaderId () const ;
string getBorrowDate () const ;
string getReturnDate () const ;
private :
string bookId;
string readerId;
string borrowDate;
string returnDate;
};
#include "BorrowRecord.h"
BorrowRecord::BorrowRecord (const string& bookId, const string& readerId, const string& borrowDate) {
this ->bookId = bookId;
this ->readerId = readerId;
this ->borrowDate = borrowDate;
this ->returnDate = "" ;
}
BorrowRecord::BorrowRecord (const string& bookId, const string& readerId, const string& borrowDate, const string& returnDate) {
this ->bookId = bookId;
this ->readerId = readerId;
this ->borrowDate = borrowDate;
this ->returnDate = returnDate;
}
void BorrowRecord::setReturnDate (string returnDate) { this ->returnDate = returnDate; }
string BorrowRecord::getBookId () const { return bookId; }
string BorrowRecord::getReaderId () const { return readerId; }
string BorrowRecord::getBorrowDate () const { return borrowDate; }
string BorrowRecord::getReturnDate () const { return returnDate; }
工具类 Utils:控制台交互优化 功能说明 :封装控制台常用工具方法(清屏、暂停、输入缓冲区清理、获取当前日期),提升交互体验。
#define _CRT_SECURE_NO_WARNINGS
#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <algorithm>
#include <vector>
#include <limits>
#include <ctime>
#include <map>
#include <sstream>
using namespace std;
class Utils {
public :
static void clearInputBuffer () ;
static void pauseConsole () ;
static string getCurrentDate () ;
};
#include "Utils.h"
void Utils::clearInputBuffer () {
cin.clear ();
cin.ignore (numeric_limits<streamsize>::max (), '\n' );
}
void Utils::pauseConsole () {
cout << "\n按任意键继续..." ;
cin.get ();
}
string Utils::getCurrentDate () {
time_t now = time (0 );
tm* ltm = localtime (&now);
char date[20 ];
sprintf (date, "%04d-%02d-%02d" , 1900 + ltm->tm_year, 1 + ltm->tm_mon, ltm->tm_mday);
return string (date);
}
系统核心类 LibrarySystem:业务逻辑总控 LibrarySystem 是系统的'大脑',整合了图书管理、读者管理、借阅归还、数据持久化 四大核心功能,通过 STL 容器实现高效数据操作。
#pragma once
#include "Utils.h"
#include "Book.h"
#include "Reader.h"
#include "BorrowRecord.h"
#include <vector>
#include <map>
#include <fstream>
#include <algorithm>
class LibrarySystem {
public :
LibrarySystem ();
~LibrarySystem ();
void addBook (Book* book) ;
Book* findBook (string id) ;
void deleteBook (const string& bookId) ;
void showAllBooks () const ;
void addReader (Reader* reader) ;
Reader* findReader (string readerId) ;
void deleteReader (const string& readerId) ;
void showAllReaders () const ;
bool borrowBook (string bookId, string readerId) ;
bool returnBook (string bookId) ;
void showBorrowRecordByReader (const string& readerId) ;
void saveData () ;
void loadData () ;
int getReaderCount () const ;
int getBookCount () const ;
int getBorrowedBookCount () const ;
friend void printReport (LibrarySystem& sys) ;
private :
vector<Book*> books;
map<string, Book*> bookMap;
vector<Reader*> readers;
map<string, Reader*> readerMap;
vector<BorrowRecord> borrowRecords;
vector<string> split (string s, char delim) ;
};
void printReport (LibrarySystem& sys) ;
#include "LibrarySystem.h"
LibrarySystem::LibrarySystem () {
loadData ();
}
LibrarySystem::~LibrarySystem () {}
void LibrarySystem::addBook (Book* book) {
if (findBook (book->getBookId ()) != nullptr ) {
cout << "图书编号 [" << book->getBookId () << "] 已存在,添加失败" << endl;
return ;
}
books.push_back (book);
bookMap[book->getBookId ()] = book;
cout << "图书《" << book->getBookName () << "》添加成功!" << endl;
}
Book* LibrarySystem::findBook (string id) {
auto it = bookMap.find (id);
if (it != bookMap.end ()) {
return it->second;
}
return nullptr ;
}
void LibrarySystem::deleteBook (const string& bookId) {
Book* book = findBook (bookId);
if (book == nullptr ) {
cout << "图书编号 [" << bookId << "] 不存在,删除失败!" << endl;
return ;
}
if (book->getIsBorrowed ()) {
cout << "图书《" << book->getBookName () << "》已借出,无法删除!" << endl;
return ;
}
books.erase (remove (books.begin (), books.end (), book), books.end ());
bookMap.erase (bookId);
delete book;
cout << "图书编号 [" << bookId << "] 删除成功!" << endl;
}
void LibrarySystem::showAllBooks () const {
if (books.empty ()) {
cout << "系统中暂无图书数据!" << endl;
return ;
}
cout << "================所有图书信息=================" << endl;
int index = 1 ;
for (Book* book : books) {
cout << index << "." ;
book->showInfo ();
index++;
cout << endl;
}
cout << "============================================" << endl;
}
void LibrarySystem::addReader (Reader* reader) {
if (findReader (reader->getReaderId ()) != nullptr ) {
cout << "读者编号【" << reader->getReaderId () << "】已存在,添加失败!" << endl;
return ;
}
readers.push_back (reader);
readerMap[reader->getReaderId ()] = reader;
cout << "读者【" << reader->getName () << "】添加成功!" << endl;
}
Reader* LibrarySystem::findReader (string readerId) {
auto it = readerMap.find (readerId);
if (it != readerMap.end ()) {
return it->second;
}
return nullptr ;
}
void LibrarySystem::deleteReader (const string& readerId) {
Reader* reader = findReader (readerId);
if (reader == nullptr ) {
cout << "读者编号【" << readerId << "】不存在,删除失败!" << endl;
return ;
}
if (reader->getBorrowCount () > 0 ) {
cout << "读者【" << reader->getName () << "】仍有未归还图书,无法删除!" << endl;
return ;
}
readers.erase (remove (readers.begin (), readers.end (), reader), readers.end ());
readerMap.erase (readerId);
delete reader;
cout << "读者编号【" << readerId << "】删除成功!" << endl;
}
void LibrarySystem::showAllReaders () const {
if (readers.empty ()) {
cout << "\n系统中暂无读者数据!" << endl;
return ;
}
cout << "\n==================== 所有读者信息 ====================" << endl;
int index = 1 ;
for (Reader* reader : readers) {
cout << index << ". " ;
reader->showInfo ();
index++;
cout << endl;
}
cout << "======================================================" << endl;
}
bool LibrarySystem::borrowBook (string bookId, string readerId) {
Book* book = findBook (bookId);
Reader* reader = findReader (readerId);
if (book == nullptr || reader == nullptr ) {
return false ;
}
if (book->getIsBorrowed ()) {
return false ;
}
if (reader->getBorrowCount () >= reader->borrowLimit ()) {
return false ;
}
book->setIsBorrowed (true );
reader->BorrowCountAdd ();
string date = Utils::getCurrentDate ();
borrowRecords.emplace_back (bookId, readerId, date);
return true ;
}
bool LibrarySystem::returnBook (string bookId) {
Book* book = findBook (bookId);
if (book == nullptr ) {
return false ;
}
if (!book->getIsBorrowed ()) {
return false ;
}
string date = Utils::getCurrentDate ();
for (auto & record : borrowRecords) {
if (record.getBookId () == bookId && record.getReturnDate ().empty ()) {
record.setReturnDate (date);
Reader* reader = findReader (record.getReaderId ());
if (reader) reader->BorrowCountSub ();
book->setIsBorrowed (false );
return true ;
}
}
return false ;
}
void LibrarySystem::showBorrowRecordByReader (const string& readerId) {
bool hasRecord = false ;
cout << "\n【读者编号:" << readerId << "】的借阅记录:" << endl;
for (auto & record : borrowRecords) {
if (record.getReaderId () == readerId) {
cout << "图书编号:" << record.getBookId () << " | 借阅日期:" << record.getBorrowDate () << " | 归还状态:"
<< (record.getReturnDate ().empty () ? "未归还" : "已归还(" + record.getReturnDate () + ")" ) << endl;
hasRecord = true ;
}
}
if (!hasRecord) {
cout << "暂无借阅记录!" << endl;
}
}
void LibrarySystem::saveData () {
ofstream bookFile ("data/books.txt" ) ;
for (Book* book : books) {
NovelBook* novel = dynamic_cast <NovelBook*>(book);
TextBook* text = dynamic_cast <TextBook*>(book);
if (novel) {
bookFile << novel->getBookId () << "," << novel->getBookName () << "," << novel->getAuthor () << ","
<< novel->getNovelType () << "," << (novel->getIsBorrowed () ? "1" : "0" ) << endl;
} else if (text) {
bookFile << text->getBookId () << "," << text->getBookName () << "," << text->getAuthor () << ","
<< text->getGrade () << "," << (text->getIsBorrowed () ? "1" : "0" ) << endl;
}
}
bookFile.close ();
ofstream readerFile ("data/readers.txt" ) ;
for (Reader* reader : readers) {
StudentReader* stu = dynamic_cast <StudentReader*>(reader);
TeacherReader* tea = dynamic_cast <TeacherReader*>(reader);
if (stu) {
readerFile << stu->getReaderId () << "," << stu->getName () << "," << stu->getStudentId () << "," << stu->getBorrowCount () << endl;
} else if (tea) {
readerFile << tea->getReaderId () << "," << tea->getName () << "," << tea->getTeacherId () << "," << tea->getBorrowCount () << endl;
}
}
readerFile.close ();
ofstream recordFile ("data/records.txt" ) ;
for (auto & record : borrowRecords) {
recordFile << record.getBookId () << "," << record.getReaderId () << "," << record.getBorrowDate () << "," << record.getReturnDate () << endl;
}
recordFile.close ();
}
void LibrarySystem::loadData () {
cout << "正在加载本地数据..." << endl;
ifstream bookFile ("data/books.txt" ) ;
if (bookFile.is_open ()) {
string line;
while (getline (bookFile, line)) {
if (line.empty ()) continue ;
vector<string> fields = split (line, ',' );
if (fields.size () != 5 ) continue ;
string bookId = fields[0 ];
string bookName = fields[1 ];
string author = fields[2 ];
string typeField = fields[3 ];
bool isBorrowed = (fields[4 ] == "1" );
if (typeField == "科幻" || typeField == "言情" || typeField == "悬疑" ) {
books.push_back (new NovelBook (bookId, bookName, author, isBorrowed, typeField));
bookMap[bookId] = books.back ();
} else {
books.push_back (new TextBook (bookId, bookName, author, isBorrowed, typeField));
bookMap[bookId] = books.back ();
}
}
bookFile.close ();
cout << "图书数据加载完成,共" << books.size () << "本图书" << endl;
} else {
cout << "未找到图书数据文件(books.txt),将创建新数据" << endl;
}
ifstream readerFile ("data/readers.txt" ) ;
if (readerFile.is_open ()) {
string line;
while (getline (readerFile, line)) {
if (line.empty ()) continue ;
vector<string> fields = split (line, ',' );
if (fields.size () != 4 ) continue ;
string readerId = fields[0 ];
string name = fields[1 ];
string idField = fields[2 ];
int borrowCount = stoi (fields[3 ]);
if (idField.find_first_not_of ("0123456789" ) == string::npos) {
readers.push_back (new StudentReader (readerId, name, borrowCount, idField));
readerMap[readerId] = readers.back ();
} else {
readers.push_back (new TeacherReader (readerId, name, borrowCount, idField));
readerMap[readerId] = readers.back ();
}
}
readerFile.close ();
cout << "读者数据加载完成,共" << readers.size () << "名读者" << endl;
} else {
cout << "未找到读者数据文件(readers.txt),将创建新数据" << endl;
}
ifstream recordFile ("data/records.txt" ) ;
if (recordFile.is_open ()) {
string line;
while (getline (recordFile, line)) {
if (line.empty ()) continue ;
vector<string> fields = split (line, ',' );
if (fields.size () != 3 && fields.size () != 4 ) continue ;
string bookId = fields[0 ];
string readerId = fields[1 ];
string borrowDate = fields[2 ];
string returnDate = "" ;
if (fields.size () == 4 ) {
returnDate = fields[3 ];
}
if (findBook (bookId) != nullptr && findReader (readerId) != nullptr ) {
borrowRecords.emplace_back (bookId, readerId, borrowDate, returnDate);
}
}
recordFile.close ();
cout << "借阅记录加载完成,共" << borrowRecords.size () << "条记录" << endl;
} else {
cout << "未找到借阅记录文件(records.txt),将创建新数据" << endl;
}
}
int LibrarySystem::getReaderCount () const {
return readers.size ();
}
int LibrarySystem::getBookCount () const {
return books.size ();
}
int LibrarySystem::getBorrowedBookCount () const {
int count = 0 ;
for (Book* book : books) {
if (book->getIsBorrowed ()) count++;
}
return count;
}
vector<string> LibrarySystem::split (string s, char delim) {
vector<string> result;
stringstream ss (s) ;
string field;
while (getline (ss, field, delim)) {
result.push_back (field);
}
return result;
}
void printReport (LibrarySystem& sys) {
int totalBooks = sys.books.size ();
int borrowedBooks = sys.getBorrowedBookCount ();
int totalReaders = sys.readers.size ();
int overdueCount = 0 ;
for (auto & record : sys.borrowRecords) {
if (record.getReturnDate ().empty ()) overdueCount++;
}
cout << "==================== 图书馆借阅报表 ====================" << endl;
cout << "系统统计:" << endl;
cout << " - 总图书数:" << totalBooks << endl;
cout << " - 已借出图书数:" << borrowedBooks << "(占比:" << (totalBooks == 0 ? 0 : (borrowedBooks * 100.0 / totalBooks)) << "%)" << endl;
cout << " - 总读者数:" << totalReaders << endl;
cout << " - 未归还记录数:" << overdueCount << endl;
cout << "========================================================" << endl;
}
数据存储:vector 用于遍历展示,map 用于快速查找,兼顾易用性和效率;
容错逻辑:添加/删除操作前校验'是否存在''状态是否合法',避免程序异常;
数据持久化:按 CSV 格式读写文本文件,dynamic_cast 判断派生类类型,保证数据准确性;
笔误修正:原代码中 getReaderCount/getBookCount 返回值写反,已修正。
主菜单交互逻辑(main.cpp) 采用分层菜单设计 (主菜单→子菜单),支持图书管理、读者管理、借阅归还、系统管理四大模块,输入校验避免非法操作。
#include "LibrarySystem.h"
#include "Utils.h"
void bookManageMenu (LibrarySystem& sys) {
int choice = 0 ;
string bookId, bookName, author, novelType, grade;
Book* book = nullptr ;
while (true ) {
system ("cls" );
cout << "================ 图书管理子菜单 ================" << endl;
cout << "1. 添加小说图书" << endl;
cout << "2. 添加教材图书" << endl;
cout << "3. 修改图书信息" << endl;
cout << "4. 删除图书" << endl;
cout << "5. 按编号查找图书" << endl;
cout << "6. 查看所有图书" << endl;
cout << "0. 返回主菜单" << endl;
cout << "================================================" << endl;
cout << "请输入操作选项:" ;
while (!(cin >> choice)) {
Utils::clearInputBuffer ();
cout << "输入无效!请输入数字:" ;
}
Utils::clearInputBuffer ();
switch (choice) {
case 1 :
cout << "\n----- 新增小说图书 -----" << endl;
cout << "图书编号:" ;
getline (cin, bookId);
cout << "图书名称:" ;
getline (cin, bookName);
cout << "作者:" ;
getline (cin, author);
cout << "小说类型(科幻/言情/悬疑):" ;
getline (cin, novelType);
sys.addBook (new NovelBook (bookId, bookName, author, false , novelType));
cout << "小说图书添加成功!" << endl;
Utils::pauseConsole ();
break ;
case 2 :
cout << "\n----- 新增教材图书 -----" << endl;
cout << "图书编号:" ;
getline (cin, bookId);
cout << "图书名称:" ;
getline (cin, bookName);
cout << "作者:" ;
getline (cin, author);
cout << "适用年级:" ;
getline (cin, grade);
sys.addBook (new TextBook (bookId, bookName, author, false , grade));
cout << "教材图书添加成功!" << endl;
Utils::pauseConsole ();
break ;
case 3 :
cout << "\n----- 修改图书信息 -----" << endl;
cout << "请输入要修改的图书编号:" ;
getline (cin, bookId);
book = sys.findBook (bookId);
if (!book) {
cout << "图书编号不存在!" << endl;
Utils::pauseConsole ();
break ;
}
cout << "当前图书名称:" << book->getBookName () << ",请输入新名称(直接回车则不修改):" ;
getline (cin, bookName);
if (!bookName.empty ()) book->setBookName (bookName);
cout << "当前作者:" << book->getAuthor () << ",请输入新作者(直接回车则不修改):" ;
getline (cin, author);
if (!author.empty ()) book->setAuthor (author);
cout << "图书信息修改成功!" << endl;
Utils::pauseConsole ();
break ;
case 4 :
cout << "\n----- 删除图书 -----" << endl;
cout << "请输入要删除的图书编号:" ;
getline (cin, bookId);
sys.deleteBook (bookId);
Utils::pauseConsole ();
break ;
case 5 :
cout << "\n----- 查找图书 -----" << endl;
cout << "请输入图书编号:" ;
getline (cin, bookId);
book = sys.findBook (bookId);
if (book) {
cout << "\n【图书信息】" << endl;
if (NovelBook* novel = dynamic_cast <NovelBook*>(book)) novel->showInfo ();
else if (TextBook* text = dynamic_cast <TextBook*>(book)) text->showInfo ();
} else {
cout << "未找到该图书!" << endl;
}
Utils::pauseConsole ();
break ;
case 6 :
cout << "\n----- 全量图书列表 -----" << endl;
sys.showAllBooks ();
Utils::pauseConsole ();
break ;
case 0 :
return ;
default :
cout << "无效选项!请重新输入。" << endl;
Utils::pauseConsole ();
break ;
}
}
}
void readerManageMenu (LibrarySystem& sys) {
int choice = 0 ;
string readerId, name, studentId, teacherId;
Reader* reader = nullptr ;
while (true ) {
system ("cls" );
cout << "================ 读者管理子菜单 ================" << endl;
cout << "1. 添加学生读者" << endl;
cout << "2. 添加教师读者" << endl;
cout << "3. 修改读者信息" << endl;
cout << "4. 删除读者" << endl;
cout << "5. 按编号查找读者" << endl;
cout << "6. 查看所有读者" << endl;
cout << "0. 返回主菜单" << endl;
cout << "================================================" << endl;
cout << "请输入操作选项:" ;
while (!(cin >> choice)) {
Utils::clearInputBuffer ();
cout << "输入无效!请输入数字:" ;
}
Utils::clearInputBuffer ();
switch (choice) {
case 1 :
cout << "\n----- 新增学生读者 -----" << endl;
cout << "读者编号:" ;
getline (cin, readerId);
cout << "读者姓名:" ;
getline (cin, name);
cout << "学号:" ;
getline (cin, studentId);
sys.addReader (new StudentReader (readerId, name, 0 , studentId));
cout << "学生读者添加成功!" << endl;
Utils::pauseConsole ();
break ;
case 2 :
cout << "\n----- 新增教师读者 -----" << endl;
cout << "读者编号:" ;
getline (cin, readerId);
cout << "读者姓名:" ;
getline (cin, name);
cout << "教师工号:" ;
getline (cin, teacherId);
sys.addReader (new TeacherReader (readerId, name, 0 , teacherId));
cout << "教师读者添加成功!" << endl;
Utils::pauseConsole ();
break ;
case 3 :
cout << "\n----- 修改读者信息 -----" << endl;
cout << "请输入要修改的读者编号:" ;
getline (cin, readerId);
reader = sys.findReader (readerId);
if (!reader) {
cout << "读者编号不存在!" << endl;
Utils::pauseConsole ();
break ;
}
cout << "当前读者姓名:" << reader->getName () << ",请输入新姓名(直接回车则不修改):" ;
getline (cin, name);
if (!name.empty ()) reader->setName (name);
cout << "读者信息修改成功!" << endl;
Utils::pauseConsole ();
break ;
case 4 :
cout << "\n----- 删除读者 -----" << endl;
cout << "请输入要删除的读者编号:" ;
getline (cin, readerId);
sys.deleteReader (readerId);
Utils::pauseConsole ();
break ;
case 5 :
cout << "\n----- 查找读者 -----" << endl;
cout << "请输入读者编号:" ;
getline (cin, readerId);
reader = sys.findReader (readerId);
if (reader) {
cout << "\n【读者信息】" << endl;
if (StudentReader* stu = dynamic_cast <StudentReader*>(reader)) stu->showInfo ();
else if (TeacherReader* tea = dynamic_cast <TeacherReader*>(reader)) tea->showInfo ();
} else {
cout << "未找到该读者!" << endl;
}
Utils::pauseConsole ();
break ;
case 6 :
cout << "\n----- 全部读者列表 -----" << endl;
sys.showAllReaders ();
Utils::pauseConsole ();
break ;
case 0 :
return ;
default :
cout << "无效选项!请重新输入。" << endl;
Utils::pauseConsole ();
break ;
}
}
}
void borrowReturnMenu (LibrarySystem& sys) {
int choice = 0 ;
string bookId, readerId;
Book* book = nullptr ;
Reader* reader = nullptr ;
while (true ) {
system ("cls" );
cout << "================ 借阅归还子菜单 ================" << endl;
cout << "1. 图书借阅" << endl;
cout << "2. 图书归还" << endl;
cout << "3. 查看读者借阅记录" << endl;
cout << "4. 查看图书借阅状态" << endl;
cout << "0. 返回主菜单" << endl;
cout << "================================================" << endl;
cout << "请输入操作选项:" ;
while (!(cin >> choice)) {
Utils::clearInputBuffer ();
cout << "输入无效!请输入数字:" ;
}
Utils::clearInputBuffer ();
switch (choice) {
case 1 :
cout << "\n----- 图书借阅 -----" << endl;
cout << "图书编号:" ;
getline (cin, bookId);
cout << "读者编号:" ;
getline (cin, readerId);
if (sys.borrowBook (bookId, readerId)) {
cout << "借阅成功!借阅日期:" << Utils::getCurrentDate () << endl;
} else {
cout << "借阅失败!(图书/读者不存在/已借出/达借阅上限)" << endl;
}
Utils::pauseConsole ();
break ;
case 2 :
cout << "\n----- 图书归还 -----" << endl;
cout << "请输入要归还的图书编号:" ;
getline (cin, bookId);
if (sys.returnBook (bookId)) {
cout << "归还成功!归还日期:" << Utils::getCurrentDate () << endl;
} else {
cout << "归还失败!(图书不存在/未借出)" << endl;
}
Utils::pauseConsole ();
break ;
case 3 :
cout << "\n----- 读者借阅记录 -----" << endl;
cout << "请输入读者编号:" ;
getline (cin, readerId);
sys.showBorrowRecordByReader (readerId);
Utils::pauseConsole ();
break ;
case 4 :
cout << "\n----- 图书借阅状态 -----" << endl;
cout << "请输入图书编号:" ;
getline (cin, bookId);
book = sys.findBook (bookId);
if (book) {
cout << "图书《" << book->getBookName () << "》状态:" << (book->getIsBorrowed () ? "已借出" : "可借阅" ) << endl;
} else {
cout << "图书编号不存在!" << endl;
}
Utils::pauseConsole ();
break ;
case 0 :
return ;
default :
cout << "无效选项!请重新输入。" << endl;
Utils::pauseConsole ();
break ;
}
}
}
void systemManageMenu (LibrarySystem& sys) {
int choice = 0 ;
while (true ) {
system ("cls" );
cout << "================ 系统管理子菜单 ================" << endl;
cout << "1. 生成借阅报表" << endl;
cout << "2. 手动保存数据" << endl;
cout << "3. 查看系统数据统计" << endl;
cout << "0. 返回主菜单" << endl;
cout << "================================================" << endl;
cout << "请输入操作选项:" ;
while (!(cin >> choice)) {
Utils::clearInputBuffer ();
cout << "输入无效!请输入数字:" ;
}
Utils::clearInputBuffer ();
switch (choice) {
case 1 :
cout << "\n----- 图书馆借阅报表 -----" << endl;
printReport (sys);
Utils::pauseConsole ();
break ;
case 2 :
sys.saveData ();
cout << "数据已手动保存到本地文件!" << endl;
Utils::pauseConsole ();
break ;
case 3 :
cout << "\n----- 系统数据统计 -----" << endl;
cout << "总图书数量:" << sys.getBookCount () << endl;
cout << "总读者数量:" << sys.getReaderCount () << endl;
cout << "当前借出图书数:" << sys.getBorrowedBookCount () << endl;
Utils::pauseConsole ();
break ;
case 0 :
return ;
default :
cout << "无效选项!请重新输入。" << endl;
Utils::pauseConsole ();
break ;
}
}
}
int main () {
LibrarySystem sys;
int choice = 0 ;
cout << "======================================================================" << endl;
cout << "| .----------------------. |" << endl;
cout << "| | | |" << endl;
cout << "| | | |" << endl;
cout << "| .-----------------. | LIBRARY | .-----------------. |" << endl;
cout << "| | | | | | | |" << endl;
cout << "| | [BOOKS] | | | | [READERS] | |" << endl;
cout << "| | [_____] | | | | [_____] | |" << endl;
cout << "| | [_____] | | | | [_____] | |" << endl;
cout << "| | [_____] | | | | [_____] | |" << endl;
cout << "| | [_____] | | | | [_____] | |" << endl;
cout << "| | | | | | | |" << endl;
cout << "| '-----------------' | | '-----------------' |" << endl;
cout << "| | | |" << endl;
cout << "| | | |" << endl;
cout << "| '----------------------' |" << endl;
cout << "| :: Library Management System :: |" << endl;
cout << "======================================================================" << endl;
Utils::pauseConsole ();
while (true ) {
system ("cls" );
cout << "================ 图书管理系统 ================" << endl;
cout << "1. 图书管理" << endl;
cout << "2. 读者管理" << endl;
cout << "3. 借阅归还管理" << endl;
cout << "4. 系统管理" << endl;
cout << "0. 退出系统" << endl;
cout << "=============================================" << endl;
cout << "请输入主菜单操作选项:" ;
while (!(cin >> choice)) {
Utils::clearInputBuffer ();
cout << "输入无效!请输入数字:" ;
}
Utils::clearInputBuffer ();
switch (choice) {
case 1 :
bookManageMenu (sys);
break ;
case 2 :
readerManageMenu (sys);
break ;
case 3 :
borrowReturnMenu (sys);
break ;
case 4 :
systemManageMenu (sys);
break ;
case 0 :
sys.saveData ();
cout << "\n系统已自动保存数据,感谢使用!再见~" << endl;
return 0 ;
default :
cout << "无效选项!请重新输入。" << endl;
Utils::pauseConsole ();
break ;
}
}
}
分层菜单:主菜单包含四大模块,每个模块对应子菜单,逻辑清晰;
输入校验:通过 while(!(cin >> choice)) 拦截非数字输入,clearInputBuffer 解决输入缓冲区异常;
交互优化:system("cls") 清屏、pauseConsole 暂停,提升用户体验;
自动保存:退出系统时自动调用 saveData,保证数据不丢失。
运行效果展示
程序启动界面
启动后显示个性化欢迎界面,自动加载本地数据(首次运行提示创建新文件)。
图书管理模块
支持小说/教材分类添加,自动校验编号唯一性;
可修改图书名称/作者,删除前校验'是否已借出'。
读者管理模块
区分学生/教师读者,自动设置不同借阅上限;
删除读者前校验'是否有未归还图书',避免数据异常。
借阅归还模块
借阅时校验'图书/读者存在性''图书状态''借阅上限';
归还时自动匹配借阅记录,更新图书状态和读者借阅数。
系统管理模块
生成可视化报表,展示总图书数、已借出数、未归还记录数等核心统计;
支持手动保存数据、查看系统统计。
可优化方向
登录权限 :添加管理员账号密码,区分普通/管理员操作;
模糊查询 :支持按书名、作者、姓名关键词查找图书/读者;
逾期提醒 :计算借阅时长(如超过 14 天),标记逾期未还记录;
图形界面 :用 EasyX 图形库替代控制台,提升交互体验;
智能指针 :用 unique_ptr 替代裸指针,避免内存泄漏。
总结与心得体会 通过本次图书管理系统的开发,深入理解了 C++ 面向对象的核心思想(封装、继承、多态),掌握了 STL 容器的场景化应用和文件 IO 的实际操作。开发过程中踩过不少坑:比如输入缓冲区异常导致的交互 bug、派生类类型判断错误、文件路径书写错误等,通过调试和查阅资料逐一解决,不仅提升了代码能力,也培养了'容错思维'——好的程序不仅要实现功能,还要能处理各种异常情况。这份系统完全满足 C++ 期末大作业的要求,也让我体会到'工程化代码'的重要性:规范的文件结构、清晰的注释、完善的容错逻辑,能大幅提升代码的可维护性。
相关免费在线工具 加密/解密文本 使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
Gemini 图片去水印 基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
Markdown转HTML 将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
HTML转Markdown 将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online