软件开发与创新-第一周课程设计作业
一.来源
本次二次开发的项目来源于室友的大一下学期C++大作业-书籍购物系统
二.运行环境与运行结果截图
运行环境:Clion 2024.2.4版本
运行截图:
1.主界面

2.运行演示




点击查看代码
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
using namespace std;
class Book
{
public:
string book_name;
int book_id;
string book_author;
string book_publisher;
double book_price;
};
class Customer
{
public:
string name;
string address;
string contact;
};
class ShoppingCart
{
public:
vector<Book> books;
void addBook(const Book &book)
{
books.push_back(book);
}
void removeBook(int index)
{
if (index >= 0 && index < books.size())
{
books.erase(books.begin() + index);
}
}
double TotalPrice()
{
double total = 0;
for (const auto &book : books)
{
total += book.book_price;
}
return total;
}
};
class Order
{
public:
int orderId;
Customer customer;
ShoppingCart cart;
double totalPrice;
}; // 订单处理
class FileHandler
{
public:
void writeOrderToFile(const Order &order, const string &filename)
{
ofstream file(filename);
if (file.is_open())
{
file << "Order ID: " << order.orderId << endl;
file << "Customer Name: " << order.customer.name << endl;
file << "Total Price: $" << order.totalPrice << endl;
file << "Books:" << endl;
for (const auto &book : order.cart.books)
{
file << "- " << book.book_name << " " << book.book_id << " " << book.book_price << " " << book.book_author << book.book_publisher << endl;
}
file.close();
}
}
}; // 负责将书籍信息写入文件
class Payment
{
public:
void processPayment(double amount)
{
cout << "订单处理成功,总价格为:" << amount << endl;
}
}; // 支付类
int main()
{
cout << "**********欢迎使用书籍购物结算系统**********" << endl;
cout << " 1.书籍库" << endl;
cout << " 2.购买书籍" << endl;
cout << " 3.显示已结算订单" << endl;
cout << " 0.结束" << endl;
cout << "请选择功能" << endl;
int mode;
cin >> mode;
if(mode == 1)
{
ifstream fin("G:/Dev-Cpp/Learning and Tests/C++/章节作业/CPP大作业/书籍库.txt");
if (!fin)
{
cout << "文件打开失败\n";
abort();
}
string str;
while (getline(fin,str))
{
cout << str << endl;
}
fin.close();
cout << "请选择下一步功能" << endl;
cin >> mode;
} //功能一,显示书籍库里的书籍
if (mode == 2)
{
int i; // i为要购买的书籍册数
cout << "请输入购买书籍册数" << endl;
cin >> i;
string book_name_newadd;
int book_id_newadd;
string book_author_newadd;
string book_publisher_newadd;
double book_price_newadd; // 输入每一本书籍的信息
Book book[i];
cout << "请依次输入书籍的名称 版号 作者 出版社 价格" << endl;
for (int j = 0; j < i; j++)
{
cin >> book_name_newadd >> book_id_newadd >> book_author_newadd >> book_publisher_newadd >> book_price_newadd;
book[j] = {book_name_newadd, book_id_newadd, book_author_newadd, book_publisher_newadd, book_price_newadd};
}
// 以上为书籍类的初始化
Customer customer;
string customer_name;
string customer_address;
string customer_contact;
cout << "请输入您的姓名 地址 联系方式" << endl;
cin >> customer_name >> customer_address >> customer_contact;
customer = {customer_name, customer_address, customer_contact};
// 以上为顾客类初始化
ShoppingCart cart;
for (int j = 0; j < i; j++)
{
cart.addBook(book[j]);
}
// 购物车初始化
Order order;
order.orderId = 1;
order.customer = customer;
order.cart = cart;
order.totalPrice = cart.TotalPrice();
// 第X号顾客订单处理
FileHandler fileHandler;
fileHandler.writeOrderToFile(order, "G:/Dev-Cpp/Learning and Tests/C++/章节作业/CPP大作业/订单.txt");
// 将顾客购买信息存入txt文件
Payment payment;
payment.processPayment(order.totalPrice);
// 支付处理
cout << "请选择下一步功能" << endl;
cin >> mode;
}
if(mode == 3)
{
ifstream fin("G:/Dev-Cpp/Learning and Tests/C++/章节作业/CPP大作业/订单.txt");
if (!fin)
{
cout << "文件打开失败\n";
abort();
}
string str;
while (getline(fin,str))
{
cout << str << endl;
}
fin.close();
cout << "请选择下一步功能" << endl;
cin >> mode;
} //功能3 展示已结算的订单
if(mode == 0)
{
cout<<"谢谢使用,再见"<<endl;
}
}
三.主要问题
- 类型问题: 在初次使用并且分析代码时,我就发现了在设计book类时,书的版号不可能只是简单的int类型,最起码应该修改为string类型
2.代码的重复:在1.书籍库,2.显示已结算订单这两个功能中,文件读取和输出的代码有大量重复,显得比较冗杂,所以我觉得应该封装一个函数来读取文件,这也可以提高代码的复用性
3.健壮性的匮乏:在大二上学习数据结构时,我了解了一个好的程序应该具有健壮性,输入数据非法,如输入的mode可能不是有效的选项,输入的书籍价格可能为负数等。可以添加输入验证逻辑,增强程序的健壮性,避免产生莫名其妙的结果
4.代码的逻辑问题:在mode2功能里,订单 ID 被固定为 1。在实际的书籍管理系统中,订单 ID 应该是唯一且递增的,需要设计一个函数来生成订单ID
5.main函数过长:在阅读代码时,我发现main函数中的代码过于冗长,包含了过多的逻辑。我觉得可以将不同的功能模块封装成独立的函数,提高代码的可读性和可维护性
6.购买书籍的函数设计太过于复杂:我在自己运行代码时发现结算需要自己输入书籍的名称 版号 作者 出版社 价格,实在太过于复杂了,可以改进一下,只输入书名来购买
四.修改后的新代码
1.对于问题1
点击查看代码
class Book {
public:
string book_name;
string book_id;
string book_author;
string book_publisher;
double book_price;
};
2.对于问题2,设计了一个readFile函数
点击查看代码
void readFile(const string& filename) {
ifstream fin(filename);
if (!fin) {
cout << "文件打开失败\n";
return;
}
string str;
while (getline(fin, str)) {
cout << str << endl;
}
fin.close();
}
switch (mode) {
case 1:
readFile("E:/c++ learning/书籍库.txt");
break;
case 3:
readFile("E:/c++ learning/订单.txt");
break;
// ...
}
3.对于问题3,在main函数中增加了对mode的判断
点击查看代码
int mode;
while (true) {
cout << "请选择功能" << endl;
if (!(cin >> mode)) {
cout << "输入无效,请输入一个有效的整数。" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
continue;
}
// ...
}
4.对于问题4,在原来函数的基础上通过引用传参使得id能够自加
点击查看代码
void purchaseBooks(int& orderId) {
// ...
Order order;
order.orderId = orderId++;
// ...
}
int main() {
int orderId = 1;
// ...
}
5.对于问题5 main函数的冗长的修改 将不同的模块封装为函数
点击查看代码
int mode;
while (true) {
cout << "请选择功能" << endl;
if (!(cin >> mode)) {
cout << "输入无效,请输入一个有效的整数。" << endl;
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
continue;
}
switch (mode) {
case 1:
readFile("E:/c++ learning/书籍库.txt");
break;
case 2:
purchaseBooks(orderId);
break;
case 3:
readFile("E:/c++ learning/订单.txt");
break;
case 0:
cout << "谢谢使用,再见" << endl;
return 0;
default:
cout << "无效的选择,请重新输入。" << endl;
}
}
6.对于问题6,书籍购买的改进 我修改了购买函数,这样在已有书籍库展示的情况下,我只需要输入书籍名字即可完成购买
点击查看代码
vector<Book> readBookLibrary(const string& filename) {
vector<Book> books;
ifstream fin(filename);
if (!fin) {
cout << "书籍库文件打开失败\n";
return books;
}
string line;
while (getline(fin, line)) {
Book book;
size_t pos1 = line.find('\t');
book.book_name = line.substr(0, pos1);
size_t pos2 = line.find('\t', pos1 + 1);
book.book_id = line.substr(pos1 + 1, pos2 - pos1 - 1);
size_t pos3 = line.find('\t', pos2 + 1);
book.book_author = line.substr(pos2 + 1, pos3 - pos2 - 1);
size_t pos4 = line.find('\t', pos3 + 1);
book.book_publisher = line.substr(pos3 + 1, pos4 - pos3 - 1);
book.book_price = stod(line.substr(pos4 + 1));
books.push_back(book);
}
fin.close();
return books;
}
// 根据书籍名称查找书籍信息
Book findBookByName(const vector<Book>& books, const string& name) {
for (const auto& book : books) {
if (book.book_name == name) {
return book;
}
}
return {"", "", "", "", 0};
}
void purchaseBooks(int& orderId) {
vector<Book> allBooks = readBookLibrary("E:/c++ learning/书籍库.txt");
int i;
cout << "请输入购买书籍册数" << endl;
cin >> i;
cin.ignore(numeric_limits<streamsize>::max(), '\n');
ShoppingCart cart;
for (int j = 0; j < i; j++) {
string bookName;
cout << "请输入第 " << j + 1 << " 本书的名称:" << endl;
getline(cin, bookName);
Book book = findBookByName(allBooks, bookName);
if (book.book_name.empty()) {
cout << "未找到名为 " << bookName << " 的书籍,跳过该书籍。" << endl;
} else {
cart.addBook(book);
cout << "已将 " << bookName << " 添加到购物车。" << endl;
}
}
五.重构后的运行截图


六.总结
在读别人写的代码时,不仅要明白他所写的代码是如何实现的,更要明白他的逻辑,这样才能更好的了解程序框架,从而做出修改,在本次修改的过程中,我通过学习同学代码的思路,更好地掌握了在编写一个比较大的程序时所要考虑的东西,比如各个模块之间的联系,以及相关函数的构造思路,同时也在和同学交流的过程中进一步提高了编程能力。
本次作业是训练我们的逆向软件设计和开发能力,在学习和了解的过程中,我参考了不少的资料,如这篇关于学习软件逆向开发中的方法的文章链接
以及我在博客园上学习的一篇逆向软件开发的一篇修改同学大作业的博客链接等都给了我许多启发与灵感,也让我能更加明白如何学习逆向软件开发与设计

浙公网安备 33010602011771号