书店管理系统逆向分析报告
一、程序概述
该程序为基于命令行的书店管理系统,主要功能包括买家管理、书籍管理和订单管理。支持三种买家类型(会员/普通/贵宾)的差异化折扣策略,并通过文件系统实现数据持久化存储。程序通过类继承实现多态,整体采用模块化设计思想。
点击查看代码
#include <iostream>
#include <fstream>
#include <string>
using namespace std;const int MAX_BOOKS = 100; // 假设最多有100本书
const int MAX_BUYERS = 50; // 假设最多有50个买家
const int MAX_ORDERS = 50; // 假设最多有50个订单
bool fileExists(const string& filename) {ifstream file(filename);return file.good();
}
class Order;class Buyer {
protected:string name; // 姓名int buyer_id; // 编号string address; // 地址double pay; // 费用public:friend Order;Buyer(string name, int buyer_id, string address, double pay = 0.0): name(name), buyer_id(buyer_id), address(address), pay(pay) {} // 构造函数virtual ~Buyer() = default; // 析构函数string getBuyName() const { return name; } // 取名字string getAddress() const { return address; } // 取地址double getPay() const { return pay; } // 取费用int getId() const { return buyer_id; } // 取编号void setPurchaseAmount(double amount){ pay = amount;} // 更新费用virtual void setPay() = 0;virtual void display() const = 0;
};class Member : public Buyer {
private:string leaguer_grade; // 会员级别public:// 构造函数Member(string name, int buyer_id, string address, double pay, string leaguer_grade) : Buyer(name, buyer_id, address, pay), leaguer_grade(leaguer_grade) {}// 费用折扣void setPay() override { pay *= 0.95;}// 显示会员信息void display() const override { cout << "姓名: " << name << ", ID: " << buyer_id << ", 地址: " << address<< ",费用 : " << pay << ", 会员等级: " << leaguer_grade << endl;}// 获取会员级别string getLeaguerGrade() const { return leaguer_grade; }
};class Layfolk : public Buyer {
private:// 折扣率double grade_or_discount;
public:// 构造函数Layfolk(string name, int buyer_id, string address, double pay,double grade_or_discount): Buyer(name, buyer_id, address, pay),grade_or_discount(grade_or_discount){}// 无折扣void setPay() override {}double getDiscountRate() {return grade_or_discount;}// 显示对象void display() const override { cout << "姓名: " << name << ", ID: " << buyer_id << ", 地址: " << address<< ", 费用: " << pay << endl;}
};class honouredguest : public Buyer {
private:// 折扣率double discount_rate; public:// 构造函数honouredguest(string name, int buyer_id, string address, double pay, double discount_rate): Buyer(name, buyer_id, address, pay), discount_rate(discount_rate) {}// 费用折扣void setPay() override {pay *= (1 - discount_rate);}// 显示对象void display() const override { cout << "姓名: " << name << ", ID: " << buyer_id << ", 地址: " << address<< ", 费用: " << pay << ", 折扣率: " << discount_rate << endl;}// 获取折扣率double getDiscountRate() const { return discount_rate; }
};class Book {
private:string isbn; // 书号string title; // 书名string author; // 作者string publishing; // 出版社double price; // 定价public://默认构造函数Book() = default;//构造函数Book(string isbn, string title, string author, string publishing, double price): isbn(isbn), title(title), author(author), publishing(publishing), price(price) {}// 取定价double getPrice() const { return price; } //显示函数void display() const { // 显示cout << "ISBN: " << isbn << ", Title: " << title << ", Author: " << author<< ", Publishing: " << publishing << ", Price: " << price << endl;}// 取书号string getISBN() const { return isbn; } // 取书名string getTitle() const { return title; } // 取作者string getAuthor() const { return author; } // 取出版社string getPublishing() const { return publishing; }
};class Order {
private:Buyer* buyer; // 购买者Book books[MAX_BOOKS]; // 订单中的书本int num_books; // 书本数量double total_amount; // 总金额public:// 计算总金额并设置购买者的支付金额void calculateTotal(Buyer* buyer) {total_amount = 0;for (int i = 0; i < num_books; ++i) {total_amount += books[i].getPrice();}if (buyer != nullptr) {buyer->setPurchaseAmount(total_amount);buyer->setPay();}else {}}// 构造函数Order(Buyer* buyer, Book* books, int num_books): buyer(buyer), num_books(num_books), total_amount(0) {for (int i = 0; i < num_books; ++i) {this->books[i] = books[i];}calculateTotal(buyer);}Order(Buyer* buyer, double total_amount): buyer(buyer), total_amount(total_amount){calculateTotal(buyer);}void addbookss(Book book[], int num_bookss){num_books = num_bookss;for (int i = 0; i < num_books; i++) {books[i] = book[i];}calculateTotal(buyer);}//取购买者Buyer* getBuyer() const { return buyer; }//取书本数量int getNumBooks() const { return num_books; }//取订单中的书本const Book& getBook(int index) const { return books[index]; }// 显示订单信息void display() const {buyer->display();cout << "书的顺序:" << endl;for (int i = 0; i < num_books; ++i) {books[i].display();}cout << "支付总额: " << total_amount << endl;}
}; //保存订单void saveOrders(Order* orders[], int num_orders, const string& filename) {ofstream file(filename);if (file.is_open()) {for (int i = 0; i < num_orders; ++i) {file<< orders[i]->getBuyer()->getBuyName()<<" " << orders[i]->getBuyer()->getId() << " "<< orders[i]->getBuyer()->getAddress() << " " << orders[i]->getBuyer()->getPay() << " " << orders[i]->getNumBooks() << "\n";for (int j = 0; j < orders[i]->getNumBooks(); ++j) {const Book& book = orders[i]->getBook(j);file << book.getISBN() << " " << book.getTitle() << " "<< book.getAuthor() << " " << book.getPublishing() << " "<< book.getPrice() << "\n";}}cout << "所有订单已保存到 " << filename << endl;}else {cerr << "打开文件 " << filename << " 写入失败" << endl;}}//保存买家void savebuyers(Buyer* buyers[], int num_buyers,const string& filename) {ofstream file(filename);if (file.is_open()) {for (int i = 0; i < num_buyers; ++i) {if (dynamic_cast<Member*>(buyers[i])) {file << "Member ";}else if (dynamic_cast<Layfolk*>(buyers[i])) {file << "Layfolk ";}else if (dynamic_cast<honouredguest*>(buyers[i])) {file << "honouredguest ";}file << buyers[i]->getBuyName() << " "<< buyers[i]->getId() << " "<< buyers[i]->getAddress() << " "<< buyers[i]->getPay();if (dynamic_cast<Member*>(buyers[i])) {file << " " << dynamic_cast<Member*>(buyers[i])->getLeaguerGrade();}else if (dynamic_cast<Layfolk*>(buyers[i])) {file << " " << dynamic_cast<Layfolk*>(buyers[i])->getDiscountRate();}else if (dynamic_cast<honouredguest*>(buyers[i])) {file << " " << dynamic_cast<honouredguest*>(buyers[i])->getDiscountRate();}file << "\n";}cout<< "所有买家已被保存到 " << filename << endl;}else {cerr << "无法打开 " << filename << " 进行写入" << endl;}}//保存书籍void saveBooks(const Book books[], int num_books, const string& filename) {ofstream file(filename);if (file.is_open()) {for (int i = 0; i < num_books; ++i) {file << books[i].getISBN() << " "<< books[i].getTitle() << " "<< books[i].getAuthor() << " "<< books[i].getPublishing() << " "<< books[i].getPrice() << "\n";}cout << "所有的书都保存到 " << filename << endl;}else {cerr << "无法打开 " << filename << " 进行写入" << endl;}}// 从文件加载书本信息int loadBooksFromFile(const string& filename, Book books[]) {ifstream file(filename);string isbn, title, author, publishing, price;int count = 0;if (file.is_open()) {while (file >> isbn >> title >> author >> publishing >> price && count < MAX_BOOKS) {books[count++] = Book(isbn, title, author, publishing, stod(price));}file.close();cout << "书籍信息已加载完毕" << endl;}else {cerr << "打开文件" << filename << "读取失败" << endl;}return count;}// 从文件加载购买者信息int loadBuyersFromFile(const string& filename, Buyer* buyers[]) {ifstream file(filename);string type, name, id, address, amount, grade_or_discount;int count = 0;if (file.is_open()) {while (file >> type >> name >> id >> address >> amount >> grade_or_discount && count < MAX_BUYERS) {if (type == "Member") {buyers[count++] = new Member(name, stoi(id), address, stod(amount), grade_or_discount);}else if (type == "Layfolk") {buyers[count++] = new Layfolk(name, stoi(id), address, stod(amount), stod(grade_or_discount));}else if (type == "honouredguest") {buyers[count++] = new honouredguest(name, stoi(id), address, stod(amount), stod(grade_or_discount));}}file.close();cout << "购买者信息已加载完毕" << endl;}else {cerr << "打开文件" << filename << "读取失败" << endl;}return count;}// 从文件加载订单信息int loadOrdersFromFile(const string& filename, Order* orders[], int max_orders, Buyer* buyers[], int num_buyers, Book books[], int num_books) {ifstream file(filename);string name, id, address, amount, isbn, title, author, publishing, price;int count = 0;if (file.is_open()) {while (count < max_orders && file >> name >> id >> address >> amount) {// 创建订单的买家信息Buyer* buyer12 = nullptr;for (int i = 0; i < num_buyers; ++i) {if (buyers[i]->getId() == stoi(id)) {buyer12 = buyers[i];break;}}if (buyer12 == nullptr) {// 未找到买家信息cout << "未找到买家信息:" << id << endl;continue;}// 创建订单对象orders[count] = new Order(buyer12, stod(amount));// 读取订单中的书籍信息int num_books_order;file >> num_books_order;// 创建数组来存储订单中的书籍信息Book* order_books = new Book[num_books_order];for (int i = 0; i < num_books_order; ++i) {file >> isbn >> title >> author >> publishing >> price;// 创建书籍对象并存储到数组中order_books[i] = Book(isbn, title, author, publishing, stod(price));}// 将书籍数组传递给订单对象if (orders[count]!= nullptr) {orders[count]->addbookss(order_books, num_books_order);}else { cout << "NO" << endl; }// 增加订单计数++count;}file.close();cout << count << " 个订单已加载完毕" << endl;}else {cout << "无法打开文件:" << filename << endl;}return count;}// 创建并初始化书本信息文件void createBooksFile(const string& filename) {if (!fileExists(filename)) {cout << "已自动创建默认书本信息文件" << endl;ofstream file(filename);if (file.is_open()) {file << "978-3-16-148410-0 C++Programming BjarneStroustrup Addison-Wesley 59.99\n";file << "978-0-13-110362-7 TheCProgrammingLanguage BrianKernighan PrenticeHall 49.99\n";file << "978-0-321-56384-2 EffectiveJava JoshuaBloch Addison-Wesley 39.99\n";}}}// 创建并初始化购买者信息文件void createBuyersFile(const string& filename) {if (!fileExists(filename)) {cout << "已自动创建默认购买者文件" << endl;ofstream file(filename);if (file.is_open()) {file << "Member Alice 1 Wonderland 0.0 Gold\n";file << "Layfolk Bob 2 Builderland 0.0 0\n";file << "honouredguest Charlie 3 ChocolateFactory 0.0 0.10\n";}}}// 创建并初始化订单信息文件void createOrdersFile(const string& filename) {if (!fileExists(filename)) {cout << "已自动创建默认订单文件" << endl;ofstream file(filename);if (file.is_open()) {file << "Alice 1 Wonderland 104.98\n";file << "2\n";file << "978-3-16-148410-0 C++Programming BjarneStroustrup Addison-Wesley 59.99\n";file << "978-0-13-110362-7 TheCProgrammingLanguage BrianKernighan PrenticeHall 49.99\n";file << "Bob 2 Builderland 39.99\n";file << "1\n";file << "978-0-321-56384-2 EffectiveJava JoshuaBloch Addison-Wesley 39.99\n";}}}//显示所有书籍void displayAllBooks(const Book books[], int num_books) {for (int i = 0; i < num_books; ++i) {books[i].display();}}//显示所有买家void displayAllBuyers(Buyer* buyers[], int num_buyers) {for (int i = 0; i < num_buyers; ++i) {buyers[i]->display();}}//显示所有订单void displayAllOrders(Order* orders[], int num_orders) {cout << num_orders << endl;for (int i = 0; i < num_orders; ++i) {orders[i]->display();}}//添加书籍void addBook(Book books[], int& num_books,Book newBook) {if (num_books < MAX_BOOKS) {books[num_books++] = newBook;cout << "添加成功" << endl;}else {cerr << "不能添加更多的书,已达到的最大容量" << endl;}}//添加买家void addBuyer(Buyer* buyers[], int& num_buyers, Buyer* newBuyer) {if (num_buyers < MAX_BUYERS) {buyers[num_buyers++] = newBuyer;cout << "添加成功" << endl;}else {cerr << "不能添加更多的买家,已达到的最大容量。" << endl;}}//移除书籍void removeBook(Book books[], int& num_books, const string& isbn) {int index = -1;for (int i = 0; i < num_books; ++i) {if (books[i].getISBN() == isbn) {index = i;break;}}if (index != -1) {for (int i = index; i < num_books - 1; ++i) {books[i] = books[i + 1];}--num_books;cout << "删除成功" << endl;}else {cerr << "找不到ISBN: " << isbn << " 的书" << endl;}}//移除买家void removeBuyer(Buyer* buyers[], int& num_buyers, const int ID) {int index = -1;for (int i = 0; i < num_buyers; ++i) {if (buyers[i]->getId() == ID) {index = i;break;}}if (index != -1) {for (int i = index; i < num_buyers - 1; ++i) {buyers[i] = buyers[i + 1];}--num_buyers;cout << "删除成功" << endl;}else {cerr << "没有找到ID: " << ID << " 的买家" << endl;}}//移除订单void removeOrder(Order* orders[], int num_orders, int order_id) {if (order_id > 0) {for (int i = order_id-1; i < num_orders ; ++i) {orders[i] = orders[i + 1];}cout << "删除成功" << endl;}else {cout << "没有找到ID为 " << order_id << " 的订单" << endl;}}int main() {Book books[MAX_BOOKS];Buyer* buyers[MAX_BUYERS] = { nullptr };Order* orders[MAX_ORDERS] = { nullptr };//如果存在文件就不创建的判断createBooksFile("books.txt");createBuyersFile("buyers.txt");createOrdersFile("orders.txt");//创建默认订单的函数int num_books = loadBooksFromFile("books.txt", books);int num_buyers = loadBuyersFromFile("buyers.txt", buyers);int num_orders = loadOrdersFromFile("orders.txt", orders, MAX_ORDERS, buyers, num_buyers, books, num_books);if (num_buyers > 0 && num_books > 0 || num_orders > 0) {while (true) {cout << "————————————————————" << endl;cout << "0、管理买家" << endl;cout << "1、管理书籍" << endl;cout << "2、创建新订单" << endl;cout << "3、显示所有订单" << endl;cout << "4、删除订单信息" << endl;cout << "5、保存订单到文件" << endl;cout << "6、退出" << endl;cout << "————————————————————" << endl;int choice;cin >> choice;if (choice == 0) {int opop;while (true) {cout << "————————————————————" << endl;cout << "1、添加新买家" << endl;cout << "2、删除买家" << endl;cout << "3、显示买家" << endl;cout << "4、保存到文件" << endl;cout << "5、返回到主函数" << endl;cout << "————————————————————" << endl;cin >> opop;if (opop == 1) {cout << "选择买家类型 (1: Member, 2: Layfolk, 3: honouredguest): ";int type;cin >> type;cout << "输入买家的信息 (Name ID Address Pay): ";string name, address;int id;double pay;cin >> name >> id >> address >> pay;if (type == 1) {cout << "输入会员级别: ";string leaguer_grade;cin >> leaguer_grade;addBuyer(buyers, num_buyers, new Member(name, id, address, pay, leaguer_grade));}else if (type == 2) {addBuyer(buyers, num_buyers, new Layfolk(name, id, address, pay, 0));}else if (type == 3) {cout << "输入折扣率: ";double discount_rate;cin >> discount_rate;addBuyer(buyers, num_buyers, new honouredguest(name, id, address, pay, discount_rate));}else {cerr << "无效的买家类型。" << endl;}}else if (opop == 2) {cout << "输入要删除的买家的ID: ";int id;cin >> id;removeBuyer(buyers, num_buyers, id);}else if (opop == 3) {displayAllBuyers(buyers, num_buyers);}else if (opop == 4) {savebuyers(buyers, num_buyers, "buyers.txt");}else if (opop == 5) {break;}}}else if (choice == 1) {int opop;while (true) {cout << "————————————————————" << endl;cout << "1、添加新书籍" << endl;cout << "2、删除书籍" << endl;cout << "3、显示书籍" << endl;cout << "4、保存到文件" << endl;cout << "5、返回到主函数" << endl;cout << "————————————————————" << endl;cin >> opop;if (opop == 1) {string isbn;string title;string author;string publishing;double price;cout << "请输入(ISBN,书名,作者,出版社,售价)" << endl;cin >> isbn >> title >> author >> publishing >> price;addBook(books,num_books,Book(isbn, title, author, publishing, price));cout << "添加新书籍完成" << endl;}else if (opop == 2) {string id;cout << "输入要删除ISBN ";cin >> id;removeBook(books, num_books, id);}else if (opop == 3) {displayAllBooks(books, num_books);}else if (opop == 4) {saveBooks(books, num_books, "books.txt");}else if (opop == 5) {break;}}}else if (choice == 2) {string buyer_name;cout << "输入买家姓名: ";cin >> buyer_name;Buyer* buyer1 = nullptr;for (int i = 0; i < num_buyers; ++i) {if (buyers[i]->getBuyName() == buyer_name) {buyer1 = buyers[i];break;}}if (buyer1) {int num_books_in_order;cout << "输入书的数量: ";cin >> num_books_in_order;if (num_books_in_order > 0 && num_books_in_order <= MAX_BOOKS) {Book books_in_order[MAX_BOOKS];for (int i = 0; i < num_books_in_order; ++i) {string isbn;cout << "输入书籍" << i + 1 << "的ISBN: ";cin >> isbn;for (int j = 0; j < num_books; ++j) {if (books[j].getISBN() == isbn) {books_in_order[i] = books[j];cout << "添加成功" << endl;break;}}}orders[num_orders++] = new Order(buyer1, books_in_order, num_books_in_order);}}else {cout << "未找到该买家\n";}}else if (choice == 3) {displayAllOrders(orders, num_orders);}else if (choice == 4) {cout << "输入订单编号(1到" << num_orders << "): ";int order_id;cin >> order_id;if (order_id > 0 && order_id <= num_orders) {removeOrder(orders, num_orders, order_id);num_orders = num_orders - 1;}else {cout << "无效的订单编号。" << endl;}}else if (choice == 5) {saveOrders(orders, num_orders, "orders.txt");}else if (choice == 6) {break;}else {cout << "无效的选项,请重试。" << endl;}}}else {cerr << "从文件加载书籍或买家信息时出错。" << endl;}for (int i = 0; i < num_buyers; ++i) {delete buyers[i];}for (int i = 0; i < num_orders; ++i) {delete orders[i];}cout << "程序结束。" << endl;return 0;}
二、功能模块分析
1. 核心类结构:
• Buyer(抽象基类)
• Member:95折会员
• Layfolk:无折扣普通买家
• honouredguest:自定义折扣率贵宾
• Book:书籍信息存储
• Order:订单管理(关联买家与书籍)
2. 数据持久化:
• 自动创建初始文件(books.txt/buyers.txt/orders.txt)
• 支持从文件加载数据
• 支持数据保存到文件
3. 用户交互:
• 分级菜单系统
• 支持增删查改操作
• 订单金额自动计算
测试内容
添加新买家
显示买家
添加新书籍及显示
添加新订单及显示
三、程序优点
1. 多态应用合理:
• 通过虚函数实现差异化折扣策略
• 买家类型扩展性强
2. 数据持久化完善:
• 三类数据独立存储
• 启动时自动加载数据
3. 模块化设计:
• 不同类职责清晰
• 文件操作函数集中管理
4. 基础功能完备:
• 实现增删改查核心功能
• 折扣计算逻辑正确
四、存在问题及分析
1. 内存管理缺陷:
问题:removeBuyer()和removeOrder()仅移动指针未释放内存
后果:导致内存泄漏,长时间运行可能耗尽内存
• 代码示例:
void removeBuyer(...) {// 删除指针后未执行delete操作for (int i = index; i < num_buyers - 1; ++i) {buyers[i] = buyers[i + 1]; // 仅移动指针}}
2. 数据结构限制:
问题:使用固定大小数组(MAX_BOOKS=100)
后果:数据量超限时程序崩溃,商业场景不适用
• 代码示例:
Book books[MAX_BOOKS]; // 固定数组声明
3. 输入验证缺失:
问题:未校验关键数据的唯一性和有效性
后果:
• 重复ISBN导致数据混乱
• 无效输入引发程序崩溃
• 典型场景:
cin >> id; // 若输入非数字字符,程序进入错误状态
4. 文件处理脆弱:
问题:未处理文件读取异常
后果:格式错误文件导致数据加载失败
• 代码示例:
while(file >> type >> name ...) // 假设文件格式绝对正确
五、改进方案
1. 内存管理优化:
// 使用智能指针管理vector<unique_ptr<Buyer>> buyers;vector<unique_ptr<Order>> orders;// 删除操作示例void removeBuyer(int index) {buyers.erase(buyers.begin() + index);}
2. 动态数据结构:
vector<Book> books; // 替换固定数组books.reserve(100); // 预分配空间提升性能
3. 增强输入验证:
//代码template<typename T>T getValidInput(const string& prompt) {T value;while (true) {cout << prompt;if (cin >> value) break;cin.clear();cin.ignore(numeric_limits<streamsize>::max(), '\n');cout << "输入无效,请重新输入!" << endl;}return value;}
4. 完善文件处理:
//完善文件处理class FileManager {public:static void loadBooks(vector<Book>& books) {// 添加异常处理try {ifstream file("books.txt");if (!file) throw runtime_error("文件打开失败");// 添加格式校验逻辑}catch (const exception& e) {cerr << "错误: " << e.what() << endl;// 恢复默认数据或终止加载}}};
六、安全性改进
数据加密:
• 敏感信息(如折扣率)加密存储
• 使用AES算法加密数据文件