1.设计题目
网上购书的一般流程是:用户根据自己的需求将所选书籍放入到购书框,选择结束后,输入自己的名字进行结账,系统会自动生成相应订单。
模拟网上购书系统,要求根据不同的顾客,按照不同的计费标准进行收费.根据实际情况,确定了购书人可分为3类:普通人、会员、贵宾。
要求:客户信息、书籍信息、订单信息数据用二进制问文件进行读取。
2.系统环境
硬件:系统类型: 64 位操作系统, 基于 x64 的处理器
软件:操作系统为Windows 10,工作软件为:Dev-c++ 5.11
3.设计内容
3.1问题分析
系统要求实现如下功能:
1.系统后台
1.原有数据:利用二进制文件当作购书系统的数据库,存储书籍信息、用户信息、订单信息。
2.添加信息:在原有数据库的基础上,有新的客户信息需要录入,需要二进制文件的读写操作进行存储和读取数据库内的信息。
2.系统前台
1.购书者查看系统的录入客户信息
2. 购书者添加自己的个人信息
3. 购书者查看系统中所有的书籍信息
4. 购书者根据个人的需求进行选择性购买
5. 购书者结账时输入自己名字进行优惠购买
6. 购书者购买完成后查看自己买的书籍订单
3.2框架及数据设计
1.设计框架
客户需求流程图
利用循环语句及switch
语句实现功能模块多次执行,代码如下
void show() { int n; while (1) { menu_show(); cin >> n; switch (n) { case (7) : { cout << "欢迎下次光临,祝您生活愉快!" << endl; return; } case (1): { show_file2();//书本信息显示函数 break; } case (2): { show_file1();//客户信息显示函数 break; } case (3):{ purchase();//选购书籍 break; } case(4) :{ pay();//结算总额 break; } case(5):{ order_show();//订单显示 break; } case (6) : { explation();//使用说明 break; } } } }
设计主菜单
部分模块设置了回退功能
if(条件) return;//返回主菜单
个人信息、书籍信息、订单信息等都是由多个基础的数据类型共同组成,因此,使用类进行封装存储。类中的基础数据类型包括浮点型、整形、字符数组、整形数组。在条件允许的情况下,应多使用new
、delete
函数以节省空间
2.定义宏数据
const int book_idlength=20;//书编号长度 const int book_10=20;//书名长度 const int book_authorlength=20;//书作者名长度 const int book_publishinglength=20;//书出版社长度 const int ordermax=10;//购买书籍种类上限 //以下变量多个函数同时要用,定义为全局变量 int A[ordermax+1]={0},id=0;//i代表购书号,A[i]代表数量,用此记录已购书籍信息 ,id记录购买者编号 double sum=0; //已选购书籍总价 char nam[10];//购买者名字
此处定义的部分宏变量,A[i]
数组i
代表购书号,A[i]
代表数量,用此记录已购书籍信息 ,id
记录购买者编号,sum
记录本次购书总额,这些数据由于在选购书籍,结算总额时都会用到,分别于俩个不同函数中,因此使用全局变量。
注:鉴于文件中读写问题,以上宏定义数据在系统录入数据后一律不得修改,否则将会产生二进制文件读写问题
3.类的应用
源代码中包含了一个基类buyer
,以及基类buyer
的3个共有继承派生类,分别是member
(会员类)、honoured_guest
(贵宾类)、layfolk
(普通类)类,派生类的作用是储存不同的顾客信息并收取不同的费用。除此之外,还有book
、order
类。
buyer
派生类的继承关系图
它们实现的功能如下
buyer
类:
保护数据成员(便于派生类成员函数访问)
name[10]//记录购书人姓名 buyerID//记录购书人编号 address[10]//记录购书人地址 pay//记录购书人应付额
公有成员函数
Buyer() 俩个构造函数 char *getbuyname();char *getaddress();double getpay();int getid();//分别用于获取姓名、地址、应付额、编号
layfolk
类:
公有继承的基础上增加了俩个公有成员函数:
void display1(); //显示函数,输出客户信息 double setpay1(double p); //计算优惠后购书金额并返回
member
类
公有继承的基础上增加了一个私有数据
int leaguer_grade; //表示会员级别
俩个公有成员函数
void display3(); //显示函数,输出客户信息 double setpay3(double p);// //计算优惠后购书金额并返回
honoured_guest
类
公有继承的基础上增加了一个私有数据
double discount_rate; //表示折扣率
俩个公有成员函数
void display2(); //显示函数,输出客户信息 double setpay3(double p);// //计算优惠后购书金额并返回
book
类
私有数据成员:(此处含有常变量数组)
char bookid[book_idlength];//记录书的编号 char book_name[book_10];// 记录书名 char author[book_authorlength];// 记录作者 char publishing[book_publishinglength];// 记录出版社 double price;// 记录价格 int buyid;//购书号,便于客户选购书籍,此代码中规定购书号不超过宏定义数据ordermax
公有成员函数:
构造函数:
book(); //用于指针开辟空间且不初始化,比如 book *p=new book(); book(char a[10],char b[10],char c[10],char d[10],double pr,int i);//用于初始化数据
成员函数
void display(); //展示书的具体信息 char* getbook_id(); //获得书的编号 char* getbook_name();//获得书的书名 char* getauthor();//获得书的作者 char* getpublishing();//获得书的出版社 double getprice(); //获得书的价格 int get_buyid();//获得书的购买号
order
类
私有数据
int orderid;//订单编号,随机函数随机生成 int buyid; // 购书人编号 char name[10];//购书人名字 double pay; //应付金额 int od[ordermax+1];//该数列用于存储书籍信息,下标代表购书号,相应数组元素代表该书的购买数量
公有成员函数
order();//构造函数,用于指针开辟空间且不初始化,比如 order *p=new order() order(int a,int b,char n[],int m[],double p)//构造函数,初始化数据 char * get_name()//获得购书者名字,便于查询订单信息 void display()//用于输出订单信息
注意事项:
1.以上各个类中的字符数组均不能换成string
类,在存入二进制文件时,string
型数据存入的是指针,二进制文件是不能存储指针的
2.使用基类虚函数display()
会出现bug,因此此处取消使用虚函数display()
4.二进制文件
该系统中共建立了4个二进制文件,分别是“客户信息.dat”,“书籍信息.dat”,“flag.dat”,“order.dat”
。引用二进制文件,<fstream>
头文件是不可少的,其次,c++中的利用文件流进行读写文件,因此使用时需要定义文件流对象,每次以二进制方式打开文件并检查是否成功打开
3.3读文件信息并输出
对于book
、order
俩大类而言,每次存储的信息长度一样,因此每次二进制文件读写指针移动的距离一样,通过简单的循环即可完成读写
下面以book
为例(仅显示该部分读文件功能代码)
ifstream i; i.open("书籍信息.dat", ios::binary);//同时具备读写功能会出问题,编译器不报错 if (!i) { cout << "书籍信息文件打开失败!" << endl; exit(1); } i.seekg(0, ios::end); int filelen; filelen = i.tellg();//获取文件长度 i.seekg(0, ios::beg);//移动指针位置 while (filelen != i.tellg()){ book *p=new book(); i.read((char*)p,sizeof(book)); p->display(); delete p; } i.close();
上述流程为利用seekg
函数先将文件指针移动至文件末尾,利用tell()
函数获得文件长度,再利用seekg
函数将文件指针移动回文件首,然后进行循环读文件,直至文件指针至文件末尾
上述代码流程图如下
上述俩大类读文件方式并不适用于客户信息.dat
文件,原因是该二进制问文件存储了不同的三大类:layfolk、member、honoured_guest
类,这就导致了第一个问题:每次读文件时,read
函数中要求移动的字节数不同,其次,不同的类输出数据信息的函数也不同(他们有着不同的display()
函数)
.鉴于此,读取书籍信息.dat
、order.dat
文件的方法不适用于读客户信息.dat
文件。于是,flag.dat
文件的作用便发挥出来了。我们通过在存储某各类至客户信息.dat
文件时,同时存入一个标志字符至flag.dat
文件中,这样就形成了一一对应的关系,通过读flag.dat
文件中的标志字符来确定什么时候客户信息.dat
文件读取结束、每次读客户信息.dat
文件时要给read
函数多少字节、利用哪个类来获取文件数据。通过flag.dat
文件,使得本混乱的客户信息.dat
文件变得有序起来
下面我们以字符0
标记layfolk
类,字符1
标记honoured_guest
类,字符2
标记member
类
上述过程功能代码如下(void user_show()
函数)
ifstream it1, it2; it1.open("客户信息.dat", ios::binary);//同时具备读写功能会出问题,编译器不报错 if (!it1) { cout << "客户信息文件打开失败!" << endl; exit(1); } it2.open("flag.dat", ios::binary ); if (!it2) { cout << "标记文件打开失败!"; exit(1); } it2.seekg(0, ios::end); int filelen; filelen = it2.tellg();//获取"flag.dat"文件长度 it2.seekg(0, ios::beg); it1.seekg(0, ios::beg);//移动指针位置 while (filelen != it2.tellg()) { char c; it2.read(&c, sizeof('1'));//字符和字符串占用的空间不一样 if (c == '0') { layfolk *p1 = new layfolk(); it1.read((char *)p1, sizeof(layfolk));///输出的格式不对称,'\t'时 p1->display1(); delete p1; } if (c == '1') { honoured_guest *p2 = new honoured_guest(); it1.read((char *)p2, sizeof(honoured_guest)); p2->display2(); delete p2; } if (c == '2') { member *p3 = new member(); it1.read((char*)p3, sizeof(member)); p3->display3(); delete p3; } } it1.close(); it2.close();
上述代码存于源代码的void user_show()
函数中,user_show
函数用于显示客户信息。
上述代码流程图如下
3.4写文件
对于书籍信息.dat
、order.dat
文件写的具体过程和读差不多,只是稍加注意的是,文件打开的方式为追加(ios::app
),这样每次的订单信息才能写入文件,否则文件中只存储了本次购书系统运行产生的数据。
格式如下(以order.dat
文件存入订单信息为例,源代码中不进行书籍信息添加)
ofstream o; o.open("order.dat",ios::binary|ios::app); if(!o){ cout<<"order.dat文件打开失败!"<<endl; return; } order *p=new order(order_number,id,nam,A,sum); if(sum!=0) o.write((char *)p,sizeof(order)); o.close(); delete p;
对于客户信息.dat
,具体过程和读类似,只是在添加客户信息时,文件要以追加方式写文件,同时存入标志字符至flag.dat
文件。
功能代码如下(购书者添加新的信息功能处代码):
ofstream ot1, ot2; ot1.open("客户信息.dat", ios::binary | ios::app ); ot2.open("flag.dat", ios::binary | ios::app); cout << "添加普通用户输入0,贵宾输入1,会员输入2" << endl; cout << "请输入你的选择:" << endl; char ch = getchar(); ot2.write(&ch, sizeof('1')); char name[10], address[10]; double a, b, c; if (ch == '0') { cout << "请依次输入姓名、编号、地址、费用" << endl; cin >> name >> a >> address >> c; layfolk *p=new layfolk(name, a, address, c); ot1.write((char *)p, sizeof(layfolk)); delete p; } if (c == '1') { honoured_guest *p2 = new honoured_guest(); it1.read((char *)p2, sizeof(honoured_guest)); p2->display2(); delete p2; } if (c == '2') { member *p3 = new member(); it1.read((char*)p3, sizeof(member)); p3->display3(); delete p3; } ot1.close(); ot2.close();
其他的一些功能在读写四个文件的基础上都可以建立,在本程序中,通过名字查找用户折扣率并计算最终应付款,查找用户历史订单,通过购书号进行购买书籍,都是通过读文件来实现相应功能的
下面以通过名字查找历史订单的代码为例
ifstream i; i.open("order.dat",ios::binary); if(!i){ cout<<"order.dat文件打开失败!"<<endl; return; } cout<<"请输入要查询人的姓名:"<<endl; char nam[10]; cin>>nam; i.seekg(0,ios::beg); if(filelen!=0){ while(i.tellg()!=filelen){ i.read((char *)p,sizeof(order)); if(strcmp(p->get_name(),nam)==0) p->display(); }} else cout<<"暂无订单信息"<<endl;
3.5数据文件
源代码中文件数据代码如下:
此为flag.dat
和客户信息.dat
文件的数据
layfolk a1("林小茶", 1, "北京", 0), b("张三", 2, "上海", 0); honoured_guest c("王瑶瑶", 3, 0.6, "上海", 0), d("李四", 4, 0.7, "武汉", 0); member e("赵红艳", 5, 5, "广州", 0), f("王五", 6, 4, "长沙", 0); ot1.write((char *)&a1, sizeof(layfolk)); ot1.write((char *)&b, sizeof(layfolk)); //"客户信息.dat" 数据库 ot1.write((char *)&c, sizeof(honoured_guest)); //初始化起始客户信息//原有数据库 ot1.write((char *)&d, sizeof(honoured_guest)); //一一对应,‘0’对layfolk ot1.write((char *)&e, sizeof(member)); //‘1’对 honoured_guest,‘2’对member ot1.write((char *)&f, sizeof(member)); char a[6]={'0','0','1','1','2','2'}; //6与文件中数据客户信息数量相对应 for(int i=0;i<6;i++) //标记文件"flag.dat"的数据 ot1.write((char *)&a[i], sizeof('0'));
此为书籍信息.dat
文件的数据
book a1("7-302-04504-6","C++程序设计","谭浩强","清华",25,1); book a2("7-402-03388-9","数据结构","许卓群","北大",20,2); book a3("978-7-04-042744-8","高等数学","陈海杰","高等教育",38.1,3); o.write((char*)&a1,sizeof(book)); // 原始书籍数据库 o.write((char*)&a2,sizeof(book)); o.write((char*)&a3,sizeof(book));
文件中的原始数据可以按要求更改,原始数据初始化方法为,在第一次运行源代码时(以设备中不存在上述3个文件判断为第一次运行),将上述代码内容不用注释,然后运行相应功能,书籍信息显示,原有客户信息显示俩大功能都运行一次即可完成数据录入,运行一次后退出本次运行,然后将上述代码注释掉(不注释会在每一次运行时都将数据信息再录入一次),这样,文件就完成了初始化。当然,如果已有相应文件可免去上述操作
3.6异常处理
异常处理格式
try{ 被检查语句 throw 异常 } catch(异常类型1) { 进行异常处理的语句1 } catch(异常类型2) { 进行异常处理的语句2 }
流程图
在本程序中,共俩处用到了异常处理,位于功能模块购买书籍、支付总额处。前者处使用是为了避免客户输入的书籍数量为负数,后者使用是防止客户信息未存入就输入名字进行购买导致程序运行错误
书籍数量异常处理代码
cout<<"请输入你要购买的书籍购买号、以及数量:"<<endl; while(1){ try{ cin>>a[i]>>b[i]; if(b[i]<=0) //异常处理 throw b[i]; break; } catch(int i){ cout<<"数量格式错误,请重新输入!"<<endl; } }
通过循坏保证多次读取,直至读入合法数值。
上述代码中,读入a[i]
、b[i]
俩个元素值后,判断数量b[i]
是否大于0,如果小于,则当作异常处理,通过thorw
函数抛出并被catch(int)
接收,然后执行catch(int)
内的语句,提示用户输入有错误,重新输入。
如果大于0,则执行下一条语句break
,退出循环,并执行后续语句。对于支付总额功能处异常处理,原理与之类似,注意数据类型换为(char *
)
4.测试内容及结果
1.主菜单
2.书籍信息显示
书籍信息.dat
”文件内容
3.客户信息显示
flag.dat
”文件内容
客户信息.dat
”文件内容
输出面板
4.添加客户信息
客户信息.dat
文件内容
flag.dat
文件内容
5.购买书籍时的返回语句
6.选购书籍
输入非法数量数据(异常处理)
7.结账模块
测试返回程序
文件中不包含的成员(异常处理)
order.dat
文件内容
8.订单显示功能
查询本次订单
查询历史订单
查张三的订单时(此时order.dat
文件只录入了王五的订单信息)
查王五的订单时
9.使用说明
10.退出系统
5.源代码
#include <cstring> #include <fstream> #include <iostream> #include <iomanip>//控制输出格式 #include <ctime> #include <cstdlib>//生成随机数,制造订单编号(仿真) using namespace std; //const int 10=10;//设置名字长度 //const int 10=10; //地址长度 const int book_idlength = 20; //书编号长度 const int book_10 = 20; //书名长度 const int book_authorlength = 20; //书作者名长度 const int book_publishinglength = 20; //书出版社长度 const int ordermax = 10; //购买书籍种类上限 //以下变量多个函数同时要用,定义为全局变量 int A[ordermax + 1] = {0}, id = 0; //i代表购书号,A[i]代表数量,用此记录已购书籍信息 ,id记录购买者编号 double sum = 0; //已选购书籍总价 char nam[10];//购买者名字 int flag1 = 0; class buyer { protected: char name[10]; int buyerID; char address[10]; double pay; public: buyer(); buyer(char n[10], int b, char a[10], double p); char *getbuyname(); char *getaddress(); double getpay(); int getid(); //virtual void display() = 0; //virtual void setpay(double = 0) = 0; }; class member: public buyer { //会员类 int leaguer_grade; //会员级别 public: member() { } member(char n[10], int b, int l, char a[10], double p): buyer(n, b, a, p) { leaguer_grade = l; //构造函数 } void display3(); //显示函数 double setpay3(double p); }; class honoured_guest: public buyer { //贵宾类 double discount_rate; //折扣率 public: honoured_guest() { } honoured_guest(char n[10], int b, double r, char a[10], double p): buyer(n, b, a, p) { discount_rate = r; } //构造函数 void display2(); //显示函数 double setpay2(double p); //计算购书金额 }; class layfolk: public buyer { //普通人类 public: layfolk() { } layfolk(char n[10], int b, char a[10], double p): buyer(n, b, a, p) { //构造函数 } void display1(); //显示函数 double setpay1(double p); //计算购书金额 /*friend ostream &operator<<(ostream &cout, layfolk &x) { x.display(); return cout; } friend istream &operator>>(istream &cin, layfolk &x) { char name[10]; int buyerID; char address[10]; double pay; cin >> name >> buyerID >> address >> pay; strcpy(x.getbuyname,name); strcpy(x.address, address); x.pay = pay; x.buyerID = buyerID; return cin; }*/ }; buyer::buyer() { //基类的构造函数 strcpy(name, " "); buyerID = 0; strcpy(address, " "); pay = 0; } buyer::buyer(char n[10], int b, char a[10], double p = 0) { //基类的构造函数 strcpy(name, n); buyerID = b; strcpy(address, a); pay = p; } double buyer::getpay() { //取购书金额 return pay; } char *buyer::getaddress() { //取购书人地址 return address; } char *buyer::getbuyname() { //取购书人名字 return name; } int buyer::getid() { //取购书人编号 return buyerID; } void member::display3() { //会员类的显示函数 cout << "购书人姓名:" << name << '\n' ; cout << "购书人编号:" << buyerID << "\t"; cout << "购书人为会员,级别:" << leaguer_grade << "\t"; cout << "地址:" << address << "\n\n"; } double member::setpay3(double p) { //会员类的计算购书金额 if (leaguer_grade == 1) //会员级别为1 pay = .95 * p + pay; else if (leaguer_grade == 2) //会员级别为2 pay = .90 * p + pay; else if (leaguer_grade == 3) //会员级别为3 pay = .85 * p + pay; else if (leaguer_grade == 4) //会员级别为4 pay = .8 * p + pay; else if (leaguer_grade == 5) //会员级别为5 pay = .7 * p + pay; else cout << "级别错误!"; return pay; } void honoured_guest::display2() { //贵宾类的显示函数 cout << "购书人姓名:" << name << '\n' ; cout << "购书人编号:" << buyerID << "\t"; cout << "购书人为贵宾!折扣率为:" << discount_rate * 100 << "%\t"; cout << "地址:" << address << "\n\n"; } double honoured_guest::setpay2(double p) { //贵宾类计算购书金额 pay = pay + (1 - discount_rate) * p; return pay; } void layfolk::display1() { //普通类显示函数 cout << "购书人姓名:" << name << '\n' ; cout << "购书人编号:" << buyerID << "\t"; cout << "购书人为普通人" << "\t"; cout << "地址:" << address << "\n\n"; } double layfolk::setpay1(double p) { pay = pay + p; return pay; } class book { protected: char bookid[book_idlength];//书的编号 char book_name[book_10];//书名 char author[book_authorlength];//作者 char publishing[book_publishinglength];//出版社 double price;//价格 int buyid;//购书号 public: book(); book(char a[10], char b[10], char c[10], char d[10], double pr, int i); void display(); char *getbook_id(); char *getbook_name(); char *getauthor(); char *getpublishing(); double getprice(); int get_buyid(); }; book::book() { strcpy(bookid, "无输入"); strcpy(book_name, "无输入"); strcpy(author, "无输入"); strcpy(publishing, "无输入"); price = 0; } book::book(char a[10], char b[10], char c[10], char d[10], double pr, int i) { strcpy(bookid, a); strcpy(book_name, b); strcpy(author, c); strcpy(publishing, d); price = pr; buyid = i; } void book::display() { cout << "书号:" << bookid << "\t"; cout << "书名:" << book_name << "\n"; cout << "作者:" << author << "\t"; cout << "出版社:" << publishing << "\t\t"; cout << "定价" << setw(5) << price; cout << " 购书号为:" << buyid << endl << endl; } char *book::getbook_id() { return bookid; } char *book::getbook_name() { return book_name; } char *book::getauthor() { return author; } char *book::getpublishing() { return publishing; } double book::getprice() { return price; } int book::get_buyid() { return buyid; } class order { private: int orderid;//订单编号 int buyid; //购书人编号 char name[10];//购书人名字 double pay; //应付金额 int od[ordermax + 1]; public: order() { } order(int a, int b, char n[], int m[], double p) { orderid = a; buyid = b; strcpy(name, n); for (int i = 0; i <= ordermax; i++) od[i] = m[i]; pay = p; } char *get_name() { return name; } void display() { //考虑运算符重载 cout << "订单编号为:" << orderid << "\n"; cout << "购书人姓名:" << name << "\t" << "购书人编号: " << buyid << "\n"; cout << "所购书籍如下:" << endl; ifstream i; i.open("书籍信息.dat", ios::binary);//同时具备读写功能会出问题,编译器不报错 if (!i) { cout << "书籍信息文件打开失败!" << endl; exit(1); } i.seekg(0, ios::end); int filelen; filelen = i.tellg();//获取文件长度 for (int j = 1; j <= ordermax; j++) { i.seekg(0, ios::beg);//移动指针位置 while (filelen != i.tellg()) { book *p = new book(); i.read((char *)p, sizeof(book)); if (p->get_buyid() == j && od[j] > 0) cout << "书名:" << left << setw(15) << p->getbook_name() << " 数量: " << od[j] << endl; delete p; } } i.close(); cout << "本次消费总额为: " << pay << endl; } }; void show_file2() { //1.书籍信息显示函数 cout << "本店所有书籍信息如下:" << endl; ofstream o; o.open("书籍信息.dat", ios::binary | ios::app); if (!o) { cout << "书籍信息文件打开失败!" << endl; exit(1); } /*book a1("7-302-04504-6","C++程序设计","谭浩强","清华",25,1); book a2("7-402-03388-9","数据结构","许卓群","北大",20,2); book a3("978-7-04-042744-8","高等数学","陈海杰","高等教育",38.1,3); o.write((char*)&a1,sizeof(book)); // 原始书籍数据库 o.write((char*)&a2,sizeof(book)); o.write((char*)&a3,sizeof(book));*/ o.close(); ifstream i; i.open("书籍信息.dat", ios::binary);//同时具备读写功能会出问题,编译器不报错 if (!i) { cout << "书籍信息文件打开失败!" << endl; exit(1); } i.seekg(0, ios::end); int filelen; filelen = i.tellg();//获取文件长度 i.seekg(0, ios::beg);//移动指针位置 while (filelen != i.tellg()) { book *p = new book(); i.read((char *)p, sizeof(book)); p->display(); delete p; } i.close(); } void user_show() { //从"客户信息.dat"中读取客户信息 ifstream it1, it2; it1.open("客户信息.dat", ios::binary);//同时具备读写功能会出问题,编译器不报错 if (!it1) { cout << "客户信息文件打开失败!" << endl; exit(1); } it2.open("flag.dat", ios::binary ); if (!it2) { cout << "标记文件打开失败!"; exit(1); } it2.seekg(0, ios::end); int filelen; filelen = it2.tellg();//获取"flag.dat"文件长度 it2.seekg(0, ios::beg); it1.seekg(0, ios::beg);//移动指针位置 while (filelen != it2.tellg()) { char c; it2.read(&c, sizeof('1'));//字符和字符串占用的空间不一样 if (c == '0') { layfolk *p1 = new layfolk(); it1.read((char *)p1, sizeof(layfolk));///输出的格式不对称,'\t'时 p1->display1(); delete p1; } if (c == '1') { honoured_guest *p2 = new honoured_guest(); it1.read((char *)p2, sizeof(honoured_guest)); p2->display2(); delete p2; } if (c == '2') { member *p3 = new member(); it1.read((char *)p3, sizeof(member)); p3->display3(); delete p3; } } it1.close(); it2.close(); } void show_file1() { //2.客户信息添加 cout << "添加客户信息输入1,查看原有客户信息输入2" << endl; cout << "请输入你的选择:" << endl; int ch; cin >> ch; getchar();//吃掉回车 ofstream ot1, ot2; ot1.open("客户信息.dat", ios::binary | ios::app ); if (!ot1) { cout << "客户信息文件打开失败!" << endl; exit(1); } ot2.open("flag.dat", ios::binary | ios::app); if (!ot2) { cout << "标记文件打开失败!"; exit(1); } /*layfolk a1("林小茶", 1, "北京", 0), b("张三", 2, "上海", 0); honoured_guest c("王瑶瑶", 3, 0.6, "上海", 0), d("李四", 4, 0.7, "武汉", 0); member e("赵红艳", 5, 5, "广州", 0), f("王五", 6, 4, "长沙", 0); ot1.write((char *)&a1, sizeof(layfolk)); ot1.write((char *)&b, sizeof(layfolk)); //"客户信息.dat" 数据库 ot1.write((char *)&c, sizeof(honoured_guest)); //初始化起始客户信息//原有数据库 ot1.write((char *)&d, sizeof(honoured_guest)); //一一对应,‘0’对layfolk ot1.write((char *)&e, sizeof(member)); //‘1’对 honoured_guest,‘2’对member ot1.write((char *)&f, sizeof(member)); char a[6]={'0','0','1','1','2','2'}; //6与数据库客户信息数量相对应 for(int i=0;i<6;i++) //标记文件"flag.dat"数据库 ot2.write((char *)&a[i], sizeof('0'));*/ if (ch == 1) { //ot2.seekp(0,ios::end); cout << "添加普通用户输入0,贵宾输入1,会员输入2" << endl; cout << "请输入你的选择:" << endl; char ch = getchar(); ot2.write(&ch, sizeof('1')); char name[10], address[10]; double a, b, c; if (ch == '0') { cout << "请依次输入姓名、编号、地址、费用" << endl; cin >> name >> a >> address >> c; layfolk *p = new layfolk(name, a, address, c); ot1.write((char *)p, sizeof(layfolk)); delete p; } if (ch == '1') { cout << "请依次输入姓名、编号、折扣率、地址、费用" << endl; cin >> name >> a >> b >> address >> c; honoured_guest *p = new honoured_guest(name, a, b, address, c); ot1.write((char *)p, sizeof(honoured_guest)); delete p; } if (ch == '2') { cout << "请依次输入姓名、编号、会员等级、地址、费用" << endl; cin >> name >> a >> b >> address >> c; member *p = new member(name, a, b, address, c); ot1.write((char *)p, sizeof(member)); delete p; } cout << "添加客户信息成功!" << endl; } ot1.close(); ot2.close(); user_show(); } void purchase() { //3.选购函数,主要记录用户购买的书籍信息 cout << "*******购买须知:先输入所需书籍购买号,再输入相对应数量********" << endl; cout << "*******购买请输入1,退出请输入0*******" << endl; int flag = 0, i = 0, amax = 0; //进行初始化amax,避免函数调用俩次及以上时出问题 int a[ordermax] = {0}, b[ordermax] = {0}; 前者记录书的种类、后者记录书的数量,amax记录已添加几种书籍 //a[i]的值为购书号,b[i]值为a[i]中书对应数量 cin >> flag; if (flag == 1) { while (1) { //挑选书籍 cout << "请输入你要购买的书籍购买号、以及数量:" << endl; while (1) { try { cin >> a[i] >> b[i]; if (b[i] <= 0) //异常处理 throw b[i]; break; } catch (int i) { cout << "数量格式错误,请重新输入!" << endl; } } amax++, i++; cout << "继续购买输入1,退出输入0" << endl; int x; cin >> x; if (x == 0) //判断退出 break; } //从文件读取书籍信息,进行计费 //double sum=0; //记录总费用 ifstream i; i.open("书籍信息.dat", ios::binary);//同时具备读写功能会出问题,编译器不报错 if (!i) { cout << "书籍信息文件打开失败!" << endl; exit(1); } i.seekg(0, ios::end); int filelen; filelen = i.tellg();//获取文件长度 //i.seekg(0, ios::beg);//移动指针位置 for (int j = 0; j < amax; j++) { //遍历数组a,即书籍种类 i.seekg(0, ios::beg);//移动指针至起始位位置,进行遍历,类似于数列从i=0开始 while (filelen != i.tellg()) { //到末尾时结束 book *p = new book(); i.read((char *)p, sizeof(book)); if (p->get_buyid() == a[j]) { sum += p->getprice() * b[j]; } delete p; } } i.close(); //为避免重复调用此函数导致记录出错问题,用大A[]记录所有,以下是存储本次调用购买的书籍信息 for (int j = 1; j <= ordermax; j++) { //遍历A数组 for (int k = 0; k < amax; k++) //遍历a[i]数组 if (a[k] == j) A[j] += b[k]; } } else return; } void pay() { //4.结算函数,此处要求得到应付金额sum、购买人信息 flag1 = 1; //标记用户已经到达此函数 cout << "*******请确认是否已选购好所需书籍,继续结账输入1,继续选购输入0*******" << endl; cout << "请输入:" << endl; int ii; cin >> ii; if (ii == 0) return; while (1) { try { cout << "请输入您的名字:" << endl; char a[10]; cin >> a; strcpy(nam, a); //从客户信息文件遍历客户信息并找出客户信息 ifstream it1, it2; it1.open("客户信息.dat", ios::binary);//同时具备读写功能会出问题,编译器不报错 if (!it1) { cout << "客户信息文件打开失败!" << endl; exit(1); } it2.open("flag.dat", ios::binary ); if (!it2) { cout << "标记文件打开失败!"; exit(1); } it2.seekg(0, ios::end); int filelen; filelen = it2.tellg();//获取文件长度 it2.seekg(0, ios::beg); it1.seekg(0, ios::beg);//移动指针位置 int fflag = 0; while (filelen != it2.tellg()) { char c; it2.read(&c, sizeof('1')); if (c == '0') { layfolk *p1 = new layfolk(); it1.read((char *)p1, sizeof(layfolk));///输出的格式不对称,'\t'时 if (strcmp(p1->getbuyname(), a) == 0) { sum = p1->setpay1(sum); id = p1->getid(); fflag = 1; break; } delete p1; } if (c == '1') { honoured_guest *p2 = new honoured_guest(); it1.read((char *)p2, sizeof(honoured_guest)); if (strcmp(p2->getbuyname(), a) == 0) { sum = p2->setpay2(sum); id = p2->getid(); fflag = 1; break; } delete p2; } if (c == '2') { member *p3 = new member(); it1.read((char *)p3, sizeof(member)); if (strcmp(p3->getbuyname(), a) == 0) { sum = p3->setpay3(sum); id = p3->getid(); fflag = 1; break; } delete p3; } } it1.close(); it2.close(); if (fflag == 0) throw a; break; } catch (char a[10]) { cout << "未查询到您的信息,请进行登记或者重新输入,登记请输入0,重新输入请输入1:" << endl; int i; cin >> i; if (i == 0) return; } } cout << "您本次消费总额为: " << sum << endl; srand((int)time(0)); int order_number; order_number = rand() % 9000 + 1000; //订单编号为四位数 ofstream o; o.open("order.dat", ios::binary | ios::app); if (!o) { cout << "order.dat文件打开失败!" << endl; return; } order *p = new order(order_number, id, nam, A, sum); if (sum != 0) o.write((char *)p, sizeof(order)); o.close(); delete p; } void order_show() { order *p = new order(); //新建指针 ifstream i; i.open("order.dat", ios::binary); if (!i) { cout << "order.dat文件打开失败!" << endl; return; } i.seekg(0, ios::end); // int filelen;// filelen = i.tellg();//获取文件长度 i.seekg(0, ios::beg); cout << "查看本次订单输入1,查看您的历史订单输入2" << endl; int ii; cin >> ii; if (ii == 1) { if (sum != 0 && flag1 == 1) { i.seekg(-sizeof(order), ios::end); i.read((char *)p, sizeof(order)); p->display(); } else cout << "暂无订单信息" << endl; } else { cout << "请输入要查询人的姓名:" << endl; char nam[10]; cin >> nam; i.seekg(0, ios::beg); if (filelen != 0) { int f = 0; while (i.tellg() != filelen) { i.read((char *)p, sizeof(order)); if (strcmp(p->get_name(), nam) == 0) { p->display(); f = 1; break; } } if (f == 0) cout << "未查询到您的订单信息" << endl; } else cout << "暂无订单信息" << endl; } i.close(); delete p; //该客户购买完成后,进行sum,A[]归0,进行下一个客户购买,实现多次购买 sum = 0, flag1 = 0; ///上面查询本次订单进行限制 for (int j = 1; j <= ordermax; j++) A[j] = 0; } void explation() { //6.使用说明函数 cout << "购书注意事项如下:" << endl; cout << "1.输入的信息以空格或者回车键为间隔" << endl; cout << "2.书籍下单后信息不可修改" << endl; cout << "3.若您未在系统客户信息里面,需要进行登记后购买" << endl; cout << "4.书籍购买完成后进行订单查看,信息无误后可退出系统" << endl; } void menu_show() { //主页菜单栏显示函数 cout << "*************************************************************************" << endl; cout << "------------------------------网上购书系统-------------------------------" << endl; cout << " ***************************** " << endl; cout << " *** 1.书籍信息显示 *** " << endl; cout << " *** 2.客户信息显示 *** " << endl; cout << " *** 3.选购书籍 *** " << endl; cout << " *** 4.结算总额 *** " << endl; cout << " *** 5.订单显示 *** " << endl; cout << " *** 6.使用说明 *** " << endl; cout << " *** 7.退出系统 *** " << endl; cout << " ***************************** " << endl; cout << "请输入一个数字选择功能: "; } void show() { int n; while (1) { menu_show(); cin >> n; switch (n) { case (7) : { cout << "欢迎下次光临,祝您生活愉快!" << endl; return; } case (1): { show_file2();//书本信息显示函数 break; } case (2): { show_file1();//客户信息显示函数 break; } case (3): { purchase();//选购书籍 break; } case (4) : { pay();//结算总额 break; } case (5): { order_show();//订单显示 break; } case (6) : { explation();//使用说明 break; } } } } int main() { show(); return 1; }