目录
技术路线
C++、sqlite3数据库、多态(动态)
通过该程序,使用者可学习C++中的动态多态的使用,以及C++对sqlite3数据库的封装、调用。 使用C++程序设计,使用C++程序调用sqlite3数据库,并通过数据库的操作对菜单进行管理,包括菜单中菜品的增删改查,还通过数据库对订单总金额进行统计,每次顾客购买后都会实时对数据库中的销售金额进行实时的更新。 程序入口分为两个,一个是管理员入口(需要密码才能进入)管理员可以对菜单进行增删改查的操作,并且可以进行查看销售额。另一个入口是顾客入口,顾客进入无需密码,顾客可以查看菜单,并进行所需菜品的购买,购买的时候订单又被分为了两类,一类是堂食订单,一类是外卖订单,此处通过一个订单基类,派生出两个订单子类,并在此处使用了动态多态,进行对订单价格的计算,显示给顾客。除此之外,顾客还需填写配送信息或者座位信息等,生动形象得模拟了当下我们在现实生活中点餐的场景。
效果展示
程序主体
Administrator.h
#ifndef _ADMINISTRATOR_H_
#define _ADMINISTRATOR_H_
#include<iostream>
using namespace std;
#include<string>
#include<vector>
#include"sqlite.h"
#include"food.h"
#include"sell_number.h"
class Administrator
{
public:
void login();//登录函数
void add_food(sqlite &db);//添加一道菜
void delete_food(sqlite &db);//删除一道菜
void change_price(sqlite &db);//修改菜的价格
void get_menu(sqlite &db, vector <string> &v);//打印全部菜品
void get_sellnum(sqlite &db, vector <string> &v);
void show_sellnum(sqlite &db, vector <string> &v);
void showAllmoney(sqlite &db);
private:
string name;
string pwd;
};
#endif
Allmoney.h
#ifndef _ALLMONEY_H_
#define _ALLMONEY_H_
class Allmoney
{
public:
void cal(double money);
private:
double allmoney;
};
#endif
base_order.h
#ifndef _BASE_ORDER_H_
#define _BASE_ORDER_H_
#include<iostream>
using namespace std;
#include<string>
#include<vector>
#include"sqlite.h"
class base_order
{
public:
base_order(double _total = 0.0) :total(_total) {};
virtual double cal_money(sqlite &db, vector <string> &v);
virtual ~base_order() {};
//此处应该定义一个接口函数,传入指向子类对象的父类指针
void calculate(base_order *porder, sqlite &db,vector <string> &v);//在调用这个函数时,需传入当前的数据库db
protected:
//string order_number;//订单编号
//double discount; //食物折扣
double total; //总价
};
#endif
customer.h
#ifndef _CUSTOMER_H_
#define _CUSTOMER_H_
#include<iostream>
using namespace std;
#include"sqlite.h"
#include"food.h"
#include"base_order.h"
#include"takeaway_order.h"
#include"eatin_order.h"
#include<string>
#include<vector>
class customer
{
public:
void write_info();
void get_menu(sqlite &db, vector <string> &v);
void buy(sqlite &db, vector <string> &v);//传入的是当前数据库
private:
string name;
string phone_number;
string address;
};
#endif
eatin_order.h
#ifndef _EATIN_ORDER_H_
#define _EATIN_ORDER_H_
#include"base_order.h"
#include"food.h"
class eatin_order:public base_order
{
public:
eatin_order(string seat = "null") :seat_num(seat) {};
virtual double cal_money(sqlite &db, vector <string> &v);
virtual ~eatin_order() {};//析构也用虚的
void get_set();
private:
string seat_num;//座位编号
};
#endif
food.h
#ifndef _FOOD_H_
#define _FOOD_H_
#include <iostream>
using namespace std;
#include <string>
#include "sqlite.h"
class food
{
public:
void set_info();
void insert_into_table(sqlite &db);//传入的是一个数据库对象的引用,名为db
void get_new_price();//输入新价格
void modify_table(sqlite &db);
void get_dele_info();
void remove_from_table(sqlite &db);
void show_table(sqlite &db, vector <string> &v);
double get_price(sqlite &db,string name);//按食物名称查找,并返回价格
private:
string food_name;
string food_price;
};
#endif
interface.h
#ifndef _INTERFACE_H_
#define _INTERFACE_H_
#include<iostream>
using namespace std;
#include<string>
class interface
{
public:
void interface1();
void interface2();
void interface3();
};
#endif
main.h
#ifndef _MAIN_H_
#define _MAIN_H_
#include"Administrator.h"
#include"customer.h"
#include"eatin_order.h"
#include"food.h"
#include"base_order.h"
#include"sqlite.h"
#include"table_factory.h"
#include"takeaway_order.h"
#include"interface.h"
#include"sell_number.h"
#endif
sell_number.h
#ifndef _SELL_NUMBER_H
#define _SELL_NUMBER_H
#include<iostream>
using namespace std;
#include<string>
#include<vector>
#include"sqlite.h"
class sell_number
{
public:
void cout_number(sqlite &db,vector <string> &v);
void show(sqlite &db, vector <string> &v);
};
#endif
sqlite.h
#ifndef _SQLITE_H_
#define _SQLITE_H_
#include<iostream>
#include<vector>
#include"sqlite3.h"
using namespace std;
#include<string>
class sqlite
{
public:
int initdb();
int createtable(char *sql);
int insert_table(char *sql);
int delete_table(char *sql);
int update_table(char *sql);
int select_table(char *sql, vector<string> &v);
string select_from_table(char *sql);
private:
sqlite3 *pdb;//此句柄在本项目中似乎没有什么实际作用
};
#endif
table_factory.h
#ifndef _TABLE_FACTORY_H
#define _TABLE_FACTORY_H
#include"sqlite.h"
class table_factory
{
public:
void create_food_menu(sqlite &db);
void create_sell_num(sqlite &db);
void create_sell_record(sqlite &db);
};
#endif
takeaway_order.h
#ifndef _TAKEAWAY_ORDER_H_
#define _TAKEAWAY_ORDER_H_
#include"base_order.h"
#include"food.h"
#include<vector>
//外卖订单类,继承于订单类
class takeaway_order:public base_order
{
public:
takeaway_order(double _package_fee = 1.0, double _ship_fee = 4.0);//继承下来的东西,基类要初始化
virtual double cal_money(sqlite &db,vector <string> &v);
virtual ~takeaway_order() {};
//void set_info();这东西后面再加
private:
double package_fee;//打包费
double ship_fee;//运送费
};
#endif
**********************
Administrator.cpp
#include"Administrator.h"
void Administrator::login()
{
while (1)
{
cout << "请输入用户名:" << endl;
cin >> name;
cout << "请输入密码:" << endl;
cin >> pwd;
if (name == "小明") //这里读者可以自行修改一下
{
if (pwd == "123") //账号密码这里读者可以自行修改一下
{
cout << "登陆成功" << endl;
break;
}
}
else
{
cout << "登陆失败" << endl;
cout << "请重新登陆" << endl;
}
}
}
void Administrator::add_food(sqlite &db)//把数据加进表
{
food _food;
_food.set_info();
_food.insert_into_table(db);
}
void Administrator::delete_food(sqlite &db)
{
food _food;
_food.get_dele_info();
_food.remove_from_table(db);
}
void Administrator::change_price(sqlite &db)
{
food _food;
_food.get_new_price();
_food.modify_table(db);
}
//这里是把信息全部打印了
void Administrator::get_menu(sqlite &db, vector <string> &v)
{
food _food;
_food.show_table(db,v);
}
//获取销量,计划做一张表,列出对应食物的对应销量
void Administrator::get_sellnum(sqlite &db, vector <string> &v)
{
sell_number _sell;
_sell.cout_number(db, v);
}
void Administrator::show_sellnum(sqlite &db, vector <string> &v)
{
sell_number _sell;
_sell.show(db, v);
}
void Administrator::showAllmoney(sqlite &db)
{
}
Allmoney.cpp
#include"Allmoney.h"
void Allmoney::cal(double money)
{
allmoney = money;
//这里还没完全写好
}
base_order.cpp
#include"base_order.h"
double base_order::cal_money(sqlite &db, vector <string> &v)
{
return -1.0;//多态父亲这边反正总是要被覆盖的,索性就不写了
}
//这个函数是实现动态多态的关键
void base_order::calculate(base_order *porder, sqlite &db,vector <string> &v)
{
porder->cal_money(db,v);
}
customer.cpp
#include"customer.h"
void customer::get_menu(sqlite &db, vector <string> &v)
{
food _food;
_food.show_table(db,v);
}
void customer::write_info()//外卖的时候用这个吧
{
cout << "请填写配送信息" << endl;
cout << "姓名:";
cin >> name;
cout << "联系电话:";
cin >> phone_number;
cout << "配送地址:";
cin >> address;
}
//此处传入的是一个空容器,用于后续存放顾客的选择
void customer::buy(sqlite &db, vector <string> &v)
{
base_order *baseorder;//创建一个订单对象基类指针
base_order _order;//创建一个订单对象(基类)
string food_name, number;
while (1)
{
cout << "请选择菜品:";
cin >> food_name;
v.push_back(food_name);
cout << "需要的数量:";
cin >> number;
v.push_back(number);//把顾客的选择存入容器中,以便后续操作
int op = 0;
flag1:
cout << "是否继续添加?<1>是 <2>否"<<endl;
cin >> op;
if (1 == op)
{
continue;
}
else if (2 == op)
{
break;
}
else
{
cout << "输入有误,请重新选择" << endl;
goto flag1;
}
}
int op = 0;
flag2:
cout << "请选择堂食or外卖? <1>堂食 <2>外卖" << endl;
cin >> op;
if (1 == op)
{
//放入执行堂食的语句
eatin_order orderin;//创建的订单是堂食订单
orderin.get_set();//装装样子写个信息
baseorder = &orderin;
_order.calculate(baseorder,db,v);//多态开始
}
else if (2 == op)
{
write_info();//装装样子,写一下配送信息,这部分功能还未完善拓展,之后可以加进骑手,把信息给骑手
takeaway_order orderout;//创建的订单是外卖订单
baseorder = &orderout;
_order.calculate(baseorder,db,v);//多态开始
}
else
{
cout << "输入有误,请重新选择" << endl;
goto flag2;
}
}
eatin_order.cpp
#include"eatin_order.h"
void eatin_order::get_set()
{
cout << "输入落座座位编号:";
cin >> seat_num;
}
double eatin_order::cal_money(sqlite &db, vector <string> &v)
{
food _food;
auto iter = v.begin();
for (iter; iter != v.end(); iter++)
{
double money = _food.get_price(db, *iter);
iter++;
double number = stod(*iter);
total += (money * number);
}
//total = total*discount;
cout << "您共需支付" << total << "元 "<< endl;
return total;
}
food.cpp
#include"food.h"
void food::set_info()
{
cout << "请输入菜名:";
cin >> food_name;
cout << "请输入价格:";
cin >> food_price;
}
void food::insert_into_table(sqlite &db)
{
char sql[1024] = { 0 };
//注意你下面这个表名。
sprintf_s(sql,"insert into food_menu (food_name,food_price) values ('%s','%s');", food_name.data(), food_price.data());
db.insert_table(sql);
}
void food::get_new_price()
{
cout << "请输入要修改价格的菜名:";
cin >> food_name;
cout << "请输入新价格:";
cin >> food_price;
}
void food::modify_table(sqlite &db)
{
char sql[1024] = { 0 };
sprintf_s(sql,"update food_menu set food_price = '%s' where food_name = '%s';",food_price.data(),food_name.data());
//加.data的原因是,将原本string类型的数据,转换成char*类型的数据,因为sprintf要求的是char *
db.update_table(sql);
}
void food::get_dele_info()
{
cout << "请输入要删除的菜名:";
cin >> food_name;
}
void food::remove_from_table(sqlite &db)
{
char sql[1024] = { 0 };
sprintf_s(sql,"delete from food_menu where food_name = '%s';",food_name.data());
db.delete_table(sql);
}
//在表中,按名字查找食物,获取他的价格,作为函数返回值返回
double food::get_price(sqlite &db,string name)
{
char sql[1024] = { 0 };
sprintf_s(sql, "select food_price from food_menu where food_name = '%s';", name.data());
string temp = db.select_from_table(sql);
return stod(temp);//转string类型数据为double类型
}
void food::show_table(sqlite &db, vector <string> &v)
{
char sql[] = "select * from food_menu;";
db.select_table(sql, v);
auto iter = v.begin();//auto可以自动匹配上合适的数据类型
cout << "-------------菜单---------------";
cout << endl;
cout << *iter;
cout << " || ";
iter++;
cout << *iter;
cout << endl;
cout << "--------------------------------";
iter++;
cout << endl;
while (iter != v.end())
{
cout << *iter;
cout << " || ";
iter++;
cout << *iter;
cout << endl;
iter++;
}
cout << "--------------------------------";
cout << endl;
}
interface.cpp
#include"interface.h"
void interface::interface1()
{
cout << "欢迎使用自主点餐系统" << endl;
cout << "1-----------管理员入口" << endl;
cout << "2-----------顾客入口" << endl;
cout << "3-----------退出系统" << endl;
}
void interface::interface2()
{
cout << " 管理员操作界面" << endl;
cout << "1-----------查看菜单" << endl;
cout << "2-----------添加菜品" << endl;
cout << "3-----------删除菜品" << endl;
cout << "4-----------修改价格" << endl;
cout << "5-----------销量报表" << endl;
cout << "6-----------查看营收" << endl;
cout << "7-----------返回上级" << endl;
cout << "8-----------退出系统" << endl;
}
void interface::interface3()
{
cout << " 顾客操作界面" << endl;
cout << "1-----------查看菜单" << endl;
cout << "2-----------选菜购买" << endl;
cout << "3-----------返回上级" << endl;
cout << "4-----------退出系统" << endl;
}
main.cpp
#include"main.h"
int main()
{
sqlite db;//创建一个数据库对象
db.initdb();//初始化数据库
table_factory fac;//创建一个制表厂对象
fac.create_food_menu(db);//创建一张菜单表
fac.create_sell_num(db);//创建一张销量表(统计数量)
fac.create_sell_record(db);//创建一张订单记录表(统计销售额)
Administrator admin;//创建一个管理员对象
customer custo;//创建一个顾客对象
interface face;
//开始写系统的界面部分
while (1)
{
flag:
face.interface1();
int op = 0;
cin >> op;
if (3 == op)
{
return 0;
}
switch (op)
{
case(1):
admin.login();
while (1)
{
face.interface2();
vector <string> v;//创建一个容器,后面用到的频率较高
int op = 0;
cin >> op;
if (8 == op)
{
return 0;
}
switch (op)
{
case(1):
v.clear();//清理容器
admin.get_menu(db, v);
break;
case(2):
admin.add_food(db);
break;
case(3):
admin.delete_food(db);
break;
case(4):
admin.change_price(db);
break;
case(5):
//查看销量
v.clear();//清理容器
admin.show_sellnum(db, v);
break;
case(6):
cout << "此功能还未开发好"<<endl;
break;
case(7):
goto flag;
break;
default:
cout << "输入有误,请重新选择" << endl;
break;
}
}
case(2):
while (1)
{
face.interface3();
int op = 0;
cin >> op;
if (op == 4)
{
return 0;
}
switch (op)
{
case(1):
{
vector <string> v;
v.clear();//清理容器
custo.get_menu(db, v);
break;
}
case(2):
{
vector <string> v;
v.clear();//清理容器
custo.buy(db, v);
admin.get_sellnum(db, v);//将用户的选择自动入表
break;
}
case(3):
goto flag;
break;
default:
cout << "输入有误,请重新选择" << endl;
break;
}
}
}
}
return 0;
}
sell_number.cpp
#include"sell_number.h"
//传入的数据是顾客的选择,放在容器里了已经
//我们要做的就是将这些东西插入进表中就可以了
//实现实时更新销量的一个表
//sell_num表名,food_name ,number ,列名
void sell_number::cout_number(sqlite &db,vector <string> &v)
{
int i = 0;
vector <string> v3;//分容器,放名字
vector <string> v4;//分容器,放数量
for (i = 0; i < v.size(); i++)
{
//cout << v[i] << endl;
if (i % 2 == 0)
{
v3.push_back(v[i]);
}
else
{
v4.push_back(v[i]);
}
}
char sql[1024] = "select * from sell_num;";
vector <string> empty;
vector <string> v1;//分容器,放名字
vector <string> v2;//分容器,放销量
db.select_table(sql, empty);//总容器,存放了所有信息
//cout << empty[0] << endl;
if (0 != empty.size())
{
//cout << "===进这里了" << endl;
int i = 2;//为了越过两个表头信息,直接从正式元素开始
int index = 0;
for (i = 2; i < empty.size(); i++)
{
//cout << v[i] << endl;
if (i % 2 == 0)
{
v1.push_back(empty[i]);
}
else
{
v2.push_back(empty[i]);
}
}
/*
for (i = 0; i < v1.size(); i++)
{
cout << v1[i] << endl;
}
*/
//v3放的是用户传入的菜名,每一道菜都需要与v1也就是库中的全部比较一下,所以得循环嵌套
i = 0;
for (i = 0; i < v3.size(); i++)//i代表的是用户传入的数据
{
int j = 0;
int flag = 0;
for (j = 0; j < v1.size(); j++)//j标示的是从表中获取的数据
{
if (v1[j] == v3[i])//等于0说明比较成功
{
//比较成功说明有,那就需要执行的是各更新操作,update,更新一下数量
char sql[1024] = { 0 };
int temp = stoi(v2[j]) + stoi(v4[i]);
//cout << temp << endl;
char str[100] = { 0 };
_itoa_s(temp, str, 10);
sprintf_s(sql, "update sell_num set number = '%s' where food_name = '%s';", str, v3[i].data());
db.update_table(sql);
flag = 1;
}
}
if (flag != 1)
{
//一轮完后如果没有匹配上说明没有,那就需要执行的是插入操作,insert,插入新的菜名
char sql[1024] = { 0 };
sprintf_s(sql, "insert into sell_num (food_name,number) values ('%s','%s');", v3[i].data(), v4[i].data());
db.insert_table(sql);
}
}
}
else
{
int i = 0;
for (i = 0; i < v3.size(); i++)
{
char sql[1024] = { 0 };
sprintf_s(sql, "insert into sell_num (food_name,number) values ('%s','%s');", v3[i].data(), v4[i].data());
db.insert_table(sql);
}
}
}
void sell_number::show(sqlite &db, vector <string> &v)
{
char sql[] = "select * from sell_num;";
db.select_table(sql, v);
auto iter = v.begin();//auto可以自动匹配上合适的数据类型
cout << *iter;
cout << " ";
iter++;
cout << *iter;
cout << endl;
iter++;
cout << endl;
while (iter != v.end())
{
cout << *iter;
cout << " ";
iter++;
cout << *iter;
cout << endl;
iter++;
}
}
sqlite.cpp
#include"sqlite.h"
//初始化创建数据库
int sqlite::initdb()
{
int ret = sqlite3_open("restaurant.db",&pdb);
if (ret != SQLITE_OK)
{
cout << "数据库创建失败!" << endl;
return -1;
}
cout << "数据库创建(打开)成功" << endl;
return 0;
}
//创建表
int sqlite::createtable(char *sql)
{
char *errmsg = NULL;
int ret = SQLITE_OK;
ret = sqlite3_exec(pdb, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
cout << "表创建失败!" << errmsg << endl;
sqlite3_free(errmsg);
//此处不写return返回了,如果已存在这个表,不用退出。(此问题已优化)
return -1;
}
return 0;
}
//往表中插入数据
int sqlite::insert_table(char *sql)
{
char *errmsg = NULL;
int ret = sqlite3_exec(pdb, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
cout << "表插入失败!" << errmsg << endl;
sqlite3_free(errmsg);
return -1;
}
cout << "插入成功" << endl;
return 0;
}
int sqlite::delete_table(char *sql)
{
char *errmsg = NULL;
int ret = sqlite3_exec(pdb, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
cout << "删除失败!" << errmsg << endl;
sqlite3_free(errmsg);
return -1;
}
cout << "删除成功" << endl;
return 0;
}
int sqlite::update_table(char *sql)
{
char *errmsg = NULL;
int ret = sqlite3_exec(pdb, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
cout << "更新失败!" << errmsg << endl;
sqlite3_free(errmsg);
return -1;
}
cout << "更新成功" << endl;
return 0;
}
//有选择的取出
string sqlite::select_from_table(char *sql)
{
char **ppTable = NULL; //存放select的结果
char *errmsg = NULL;
int ret = sqlite3_get_table(pdb, sql, &ppTable, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
cout << "sqlite3_get_table error:" << errmsg << endl;
sqlite3_free(errmsg);
errmsg = NULL;
return "fail";
}
//cout << ppTable[1];//输出一下看看对不对
//有一点得在这里提一下,此处我们获取数据时,由于是sqlite3_get_table函数的原因,
//pptable中的第零号元素是表头,正确的选取应该选第一号元素
//此处是我起初没有注意到的地方
return ppTable[1];
}
//全部取出表中的东西,东西存在于pptable,之后再转存于容器中去
int sqlite::select_table(char *sql,vector<string> &v)
{
char **ppTable = NULL; //存放select的结果
int row = 0; //查找到的行数
int column = 0; //查到的结果的列数
char *errmsg = NULL;
int ret = sqlite3_get_table(pdb, sql, &ppTable, &row, &column, &errmsg);
if (ret != SQLITE_OK)
{
cout << "sqlite3_get_table error:" << errmsg << endl;
sqlite3_free(errmsg);
errmsg = NULL;
return -1;
}
int i = 0, j = 0;
for (i = 0; i < row + 1; i++)//此处row要加1,是因为,在返回参数时,第一行(各列名称哪行)不会被统计进去
{
for (j = 0; j < column; j++)
{
v.push_back(ppTable[i*column + j]);
//printf("%s ", ppTable[i * column + j]);
}
}
return 0;
}
table_factory.cpp
#include"table_factory.h"
void table_factory::create_food_menu(sqlite &db)
{
char table_sql[] = "create table if not exists food_menu(food_name text unique not null,food_price text not null);";
db.createtable(table_sql);
}
void table_factory::create_sell_num(sqlite &db)
{
char table_sql[] = "create table if not exists sell_num(food_name text unique not null,number text not null);";
db.createtable(table_sql);
}
void table_factory::create_sell_record(sqlite &db)
{
//amount是金额的意思
char table_sql[] = "create table if not exists sell_record(money text not null);";
db.createtable(table_sql);
}
takeaway_order.cpp
#include"takeaway_order.h"
//将打包费和配送费先定死
takeaway_order::takeaway_order(double _package_fee, double _ship_fee)
{
package_fee = _package_fee;
ship_fee = _ship_fee;
}
//此函数的形参分别是,当前数据库,以及顾客的选择容器(已有数据)
double takeaway_order::cal_money(sqlite &db,vector <string> &v)//传入的是顾客的选择
{
food _food;
auto iter = v.begin();
//cout << *iter << "一会记得删,检测用";
for(iter; iter != v.end();iter++)
{
double money = _food.get_price(db, *iter);
iter++;
double number = stod(*iter);
total += (money * number);
}
total = (total + package_fee + ship_fee);// *discount;
cout << "您共需支付" << total << "元" << endl;
return total;
}
/*void takeaway_order::set_info()
{
cout << "设定打包费:";
cin >> package_fee;
cout << "设定配送费:";
cin >> ship_fee;
}*/
#include"takeaway_order.h"
//将打包费和配送费先定死
takeaway_order::takeaway_order(double _package_fee, double _ship_fee)
{
package_fee = _package_fee;
ship_fee = _ship_fee;
}
//此函数的形参分别是,当前数据库,以及顾客的选择容器(已有数据)
double takeaway_order::cal_money(sqlite &db,vector <string> &v)//传入的是顾客的选择
{
food _food;
auto iter = v.begin();
//cout << *iter << "一会记得删,检测用";
for(iter; iter != v.end();iter++)
{
double money = _food.get_price(db, *iter);
iter++;
double number = stod(*iter);
total += (money * number);
}
total = (total + package_fee + ship_fee);// *discount;
cout << "您共需支付" << total << "元" << endl;
return total;
}