对C++书店管理系统的逆向分析
书店管理系统逆向分析报告
一、程序概述
该程序为基于命令行的书店管理系统,主要功能包括买家管理、书籍管理和订单管理。支持三种买家类型(会员/普通/贵宾)的差异化折扣策略,并通过文件系统实现数据持久化存储。程序通过类继承实现多态,整体采用模块化设计思想。
点击查看代码
#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;
// 恢复默认数据或终止加载
}
}
};