C++
一.问题描述
设计一图书信息管理系统,实现以下功能:系统以菜单方式工作,图书信息录入功能(图书 信息用文件保存) ;图书信息包括:登录号、书名、作者名、分类号、出版单位、出版时间、 价格等;图书信息浏览功能(输出所有图书信息);查询和排序功能:按书名查询(显示所有 同名的书),按作者名查询(所有该作者的书) ; 图书信息的删除与修改。
二.基本要求
(1)使用面向对象编程思想编写开发过程中需要用到的类,比如:图书类(图书信息)、日期类、管理类(实现对图书信息的管理) 。
(2)输入和输出可以使用文本文件重定向输入(保存数据为磁盘文件);也可以使用标 准输入输出进行(提交时需要提交TXT格式输入数据)。应包含 20 条以上记录,且有同姓名 不同作者的书和同一作者的多部著作,包含数据信息即图书信息。在运行程序时自动载入,若文 件不存则创建一个空文件。
(3)基本功能要求具有增、删、改、查。
三.需求分析
(1)设计的程序需要有对应的将载入内存的数据组织描述起来的数据结构,以及设计对载入内存的数据进行增删查改的算法。
(2)程序需要实现的功能:浏览图书信息;对图书进行分类排序;查找图书相关信息;增加、删除、修改图书信息。
(3)输入形式:登录号、书名、作者名、分类号、图书出版社以及出版时间全都以字符串的形式输入,书的价格以double类型输入。程序将采用标准输入输出方式,将数据保存在相应TXT文件中。
(4)整个管理类的成员函数驱动只需要一个管理类实例就完全足够,因此这种系统管理类我将使用单例模式的懒汉形式。
(5)输入案例:XC-100201 《追风筝的人》 卡勒德·胡赛尼 2 上海人民出版社 2006-05-01 36.00(输入时需注意登录号作为图书信息的分类标识,不能出现错误和重复,书籍名称添加了string类字符串匹配函数,因此书名要添加书名符)。
四.概要设计
(1)主程序流程
(2)图书类book,日期类Date的成员函数都比较相似,比如初始化对象的函数initialize,修改对象的函数modify,打印对象信息的函数show和将对象写回文件流的函数backToTxt。但是其中manager是一个独立的类:其实现的功能及函数:有添加信息,修改信息,浏览信息,按书名查找,删除信息,按图书价格排序的模板函数。最重要的是start函数和ending函数,其中start负责读文件流并初始化对象,ending负责将内存数据写回文件。
详细代码如下
Date.h
#pragma once
class Date;
template<typename _T>
void swap(_T* a, _T* b)
{
_T tmp = *a;
*a = *b;
*b = tmp;
}
class Date
{
public:
Date()
{
struct tm* tmp_time = new struct tm;
time_t t; t = time(NULL);
tmp_time = localtime(&t);
this->year = tmp_time->tm_year;
this->month = tmp_time->tm_mon;
this->day = tmp_time->tm_mday;
};
Date(int year, int month, int day, int hours, int minutes, int seconds) :
year(year), month(month), day(day) { }
//拷贝构造函数
Date(const Date& d)
{
this->year = d.year;
this->month = d.month;
this->day = d.day;
}
//将Date时间写入时间戳
void write(struct tm* t)
{
t->tm_year = year;
t->tm_mon = month;
t->tm_mday = (short)day;
}
//格式化返回当前时间组织的字符串
string curTime()
{
struct tm* tmp_time = new struct tm;
time_t t; t = time(NULL);
tmp_time = localtime(&t); //将秒组织成结构体
char s[100];
strftime(s, sizeof(s), "%Y-%m-%d", tmp_time);
string str = s;
return str;
}
//Date2string
string Date2string()
{
struct tm* tmp_time = new struct tm;
tmp_time->tm_year = year - 1900;
tmp_time->tm_mon = month - 1;
tmp_time->tm_mday = day;
char s[100];
strftime(s, sizeof(s), "%Y-%m-%d", tmp_time);
string str = s;
return str;
}
//格式化的字符转时间戳写回Date实例
void strBack2Date(string& str)
{
struct tm* tmp_time = new struct tm;
char s[100] = {0};
strcpy(s, str.c_str());
sscanf(s, "%d-%d-%d", &year, &month, &day);
}
//计算年龄
short age()
{
struct tm* tmp_time = new struct tm;
time_t t; t = time(NULL);
tmp_time = localtime(&t);
return (tmp_time->tm_year + 1900 - year);
}
void display()
{
cout << setw(4) << left << year << "." << setw(2) << left << month << "." << setw(2) << left << day << "." << " ";
}
private:
int year;
int month;
int day;
};
books.h
#pragma once
//book类
class book
{
public:
void initialize(ifstream& f)
{
string publishTime;
f >> logInNumber;
f >> bookName;
f >> author;
f >> classic;
f >> press;
f >> publishTime;
this->publishTime.strBack2Date(publishTime);
f >> price;
}
double getPrice()
{
return this->price;
}
void addPoint()
{
cout << "请依次输入:登录号、书名、作者名、分类号、出版单位、出版时间、 价格:" <<endl;
}
void changePoint()
{
cout << "请依次输入要修改的:登录号、书名、作者名、分类号、出版单位、出版时间、 价格(不需要修改的请输入0):" << endl;
}
void modify()
{
string logInNumber; string bookName;
string author; short classic;
string press; string publishTime;
double price;
cin >> logInNumber>> bookName>> author >> classic >> press>> publishTime>> price;
if (strcmp(logInNumber.c_str(), "0"))
this->logInNumber = logInNumber;
if (strcmp(bookName.c_str(), "0"))
this->bookName = bookName;
if (strcmp(author.c_str(), "0"))
this->author = author;
if (0 != classic)
this->classic = classic;
if (strcmp(press.c_str(), "0"))
this->press = press;
if (strcmp(publishTime.c_str(), "0"))
this->publishTime.strBack2Date(publishTime);
if (0 != price)
this->price = price;
}
static void title()
{
cout << "_____________________________________________________________"<<
"____________________________________"<< endl;
cout << setw(12) << left << "|登录号 " << setw(20) << left << "|书名 "
<< setw(20) << left << " |作者名 " << setw(5) << left << " |分类号 "
<< setw(15) << left << "|出版社 " << setw(5) << left << " |出版时间 "
<< setw(5) << left << "|价格 " << endl;
}
void show()
{
cout << setw(12) << left << logInNumber << setw(20) << left << bookName << " "
<< setw(20) << left << author << " " << setw(5) << left<< classic <<" "
<< setw(15) << left << press << " " << setw(5) << left << publishTime.Date2string()<<" "
<< setw(5) << left << fixed << setprecision(2)<< price << endl;
}
book* findByName(string& name)
{
if (!strcmp(bookName.c_str(), name.c_str()))
return this;
return nullptr;
}
void backToTxt(ostream& out)
{
out << logInNumber << " " << bookName << " " << author << " "
<< classic <<" "<< press<<" "<< publishTime.Date2string() << " "<< price <<'\r' << '\n';
cout << "_____________________________________________________________"<<
"____________________________________"<< endl;
}
private:
string logInNumber; //登录号
string bookName; //书名
string author; //作者名
short classic; //分类号
string press; //出版社
Date publishTime; //出版时间
double price; //价格
};
common.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <thread>
#include <vector>
using namespace std;
#include "Date.h"
#include "books.h"
#include "manager.h"
manager.h
#pragma once
//读取txt文件数据
void loiding()
{
for (int i = 0; i <= 100; i += 10)
{
printf("加载txt文件数据:%3d%%\r", i);
Sleep(99);
fflush(stdout);
}
}
//管理类
class manager
{
public:
static manager* simpleInstance()
{
return new manager;
}
void start(vector<book*>& books)
{
int lines2book = 0;
ifstream ifileInfo;
ifileInfo.open("books.txt", ios::in | ios::binary);
ifileInfo >> lines2book;
for (int i = 0; i < lines2book; ++i)
{
book* d = new book;
d->initialize(ifileInfo);
books.push_back(d);
}
ifileInfo.close();
thread th(loiding); th.join();
}
//menu(主菜单)
void menu()
{
cout << "--------------------------------------" << endl;
cout << "|*************************************|" << endl;
cout << "| 1. 添加图书信息 |" << endl;
cout << "| 2. 修改图书信息 |" << endl;
cout << "| 3. 浏览图书信息 |" << endl;
cout << "| 4. 查找图书信息 |" << endl;
cout << "| 5. 删除图书信息 |" << endl;
cout << "| 6. 按价格排序 |" << endl;
cout << "| 0. 退出并将数据保存回文件 |" << endl;
cout << "|* 请输入要执行的功能所对应的数字:";
}
//添加一条图书信息
template<typename _T1, typename _T2>
bool add(_T1& v)
{
_T2* s = new _T2;
s->addPoint();
s->modify();
v.push_back(s);
return true;
}
//修改图书信息
template<typename _T1, typename _T2>
bool modify(_T1& v, string name)
{
_T2* find = nullptr;
for (int i = 0; i < v.size(); ++i)
{
if (find = v[i]->findByName(name))
break;
}
if (nullptr != find)
{
find->changePoint();
find->modify();
return true;
}
else
{
cout << "没有找到匹配项 ";
return false;
}
}
//浏览图书信息
template<typename _T1, typename _T2>
void show(_T1& v)
{
_T2::title();
for (int i = 0; i < v.size(); ++i)
v[i]->show();
cout << endl;
}
//查找图书信息string型(按书名查找)
template<typename _T1, typename _T2>
void findByName(_T1& v, string name)
{
_T2* find = nullptr;
for (int i = 0; i < v.size(); ++i)
{
if (find = v[i]->findByName(name))
break;
}
if (nullptr != find)
{
cout << "找到了:" << endl;
find->title();
find->show();
}
else
cout << "没找到" << endl;
}
//删除图书信息
template<typename _T1, typename _T2>
bool erase(_T1& v, string name)
{
_T2* find = nullptr;
for (int i = 0; i < v.size(); ++i)
{
if (find = v[i]->findByName(name))
{
v.erase(v.begin()+i);
return true;
}
}
return false;
}
template<typename _T2>
void swap(_T2& a, _T2& b)
{
_T2 tmp = a;
a = b;
b = tmp;
}
//按图书价格排序
template<typename _T1, typename _T2> //_T2 is first ptr
void sortBySalary(_T1& v)
{
for (int i = v.size() - 1; i > 0; --i)
{
for (int j = 0; j < i; ++j)
{
if (v[j]->getPrice() > v[j + 1]->getPrice())
swap<_T2>(v[j], v[j + 1]);
}
}
}
void ending(vector<book*>& books)
{
ofstream ofileInfo("books.txt", ios::trunc | ios::out | ios::binary);
ofileInfo << books.size()<< '\r' << '\n';
for (int i = 0; i < books.size(); ++i)
books[i]->backToTxt(ofileInfo);
ofileInfo.close();
}
private:
manager() {}
};
源。cpp
#include "common.h"
int main() {
//管理类:单例模式的懒汉模式
manager* Manager = manager::simpleInstance();
vector<book*> books;
Manager->start(books);
int input = 0;
string name;
Manager->menu();
while (cin >> input && input != 0)
{
switch (input)
{
case 1:
cout << "添加一条图书信息:> " << endl;
if (Manager->add<vector<book*>, book>(books))
cout << "添加成功" << endl;
break;
break;
case 2:
cout << "修改图书信息:> " << endl;
cout << "请输入要修改的修改的图书的名称:> " << endl;
cin >> name;
if (Manager->modify<vector<book*>, book>(books, name))
cout << "修改成功" << endl;
else
cout << "修改失败" << endl;
break;
case 3:
cout << "浏览图书信息:> " << endl;
Manager->show<vector<book*>, book>(books);
break;
case 4:
cout << "查找图书信息:> " << endl;
cout << "请输入要查找的查找的图书的名称:> " << endl;
cin >> name;
Manager->findByName<vector<book*>, book>(books, name);
break;
case 5:
cout << "删除图书信息:> " << endl;
cout << "请输入要删除的图书的名称:> " << endl;
cin >> name;
if (Manager->erase<vector<book*>, book>(books, name))
cout << "删除成功" << endl;
else cout << "删除失败" << endl;
break;
case 6:
cout << "按价格排序:> " << endl;
Manager->sortBySalary<vector<book*>, book*>(books);
cout << "排序成功" << endl;
break;
default:
cout << "输入错误,请重新输入:" << endl;
}
Manager->menu();
}
Manager->ending(books);
return 0;
}
txt
XC-100101 《你坏》 大冰 1 湖南文艺出版社 2018-07-02 39.6
XC-100102 《阿弥陀佛么么哒》 大冰 1 湖南文艺出版社 2015-06-01 38
XC-100103 《小孩》 大冰 1 湖南文艺出版社 2019-06-12 39
XC-100104 《我不》 大冰 1 湖南文艺出版社 2017-09-01 39
XC-100105 《好吗好的》 大冰 1 湖南文艺出版社 2016-08-01 39
XC-100106 《乖,摸摸头》 大冰 1 湖南文艺出版社 2019-04-01 36.02
XC-100201 《追风筝的人》 卡勒德·胡赛尼 2 上海人民出版社 2006-05-01 36
XC-100202 《群山回唱》 卡勒德·胡赛尼 2 上海人民出版社 2013-08-01 36
XC-100203 《灿烂千阳》 卡勒德·胡塞尼 2 上海人民出版社 2007-09-01 36
XC-100204 《海的祈祷》 卡勒德·胡塞尼 2 上海人民出版社 2019-04-01 56
XC-100301 《自在独行》 贾平凹 3 长江文艺出版社 2016-05-01 39
XC-100302 《万物有灵》 贾平凹 3 长江文艺出版社 2019-11-01 45
XC-100303 《山本》 贾平凹 3 作家出版社 2018-03-01 59
XC-100304 《白夜》 贾平凹 3 华夏出版社 2017-02-01 49
XC-100305 《秦腔》 贾平凹 3 作家出版社 2018-11-15 50
XC-100306 《废都》 贾平凹 3 作家出版社 2018-11-09 50
XC-100401 《百年孤独》 加西亚·马尔克斯 4 南海出版公司 2017-08-01 55
XC-100402 《恶时辰》 加西亚·马尔克斯 4 南海出版公司 2013-03-01 29.5
XC-100403 《活着为了讲述》 加西亚·马尔克斯 4 南海出版公司 2016-04-17 55
XC-100404 《礼拜二f午睡时刻》 加西亚·马尔克斯 4 南海出版公司 2015-03-01 29.5
XC-100405 《迷宫中的将军》 加西亚·马尔克斯 4 南海出版公司 2014-11-01 39.5
运行结果如下: