这是一篇复习类的博客,主要综合运用以下知识:

  • 格式化输入输出及打印菜单
  • 类的封装
  • 类的组合
  • 子函数概念
  • 共享指针
  • lambda表达式

头文件

为了简便,就把类的声明和实现写在同一个VendingMachine.h文件里了

1
2
3
4
5
6
7
8
#pragma once
#include <string>
#include <vector>
#include <unordered_map>
#include <iostream>
#include <algorithm>
#include <windows.h>
using namespace std; //展开std命名空间

这里一次性给出所用的头文件,后文便不再添加了

封装商品类

售货机当然要管理商品啦,那怎么管理呢?依然是先描述,再组织

怎么描述?把它封装成商品类

1
2
3
4
5
6
7
8
9
10
11
struct Item
{
public:
Item(const string& name,double price,int cnt)
:_name(name),_price(price),_cnt(cnt)
{}
public:
string _name;
double _price;
int _cnt;
};

怎么组织?用vecotr储存,用unordered_map建立以name为键,下标为值的索引,统一管理所有商品

封装VendingMachine类

基本框架

1
2
3
4
5
6
7
8
9
10
11
12
13
class VendingMachine
{
public:
VendingMachine(int capacity = 100) :_amount(0), _sale(0),_capacity(capacity) {}

private:
vector<Item> _GoodsList; //储存商品列表
unordered_map<string, int> _index; //储存名字指向索引的哈希表

double _amount;//货物总价值
double _sale;//总销售额
int _capacity;//容量
};

实现增加货物和销售货物

这里就要使用子函数的概念了。将实际增加货物的功能和IO功能进行解耦合,封装在两个函数中。_AddItem负责实现增加货物,AddItem负责IO处理和回调_AddItem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public:
bool AddItem()
{
Info();
string name;
double price;
int num;
cout << "请先后输入 [商品名称] [单价] [数量]" << endl;
cin >> name >> price >> num;

return _AddItem(name, price, num);
}

private:
bool _AddItem(const string& name, double price,int num)
{
if (_index.count(name))
{
//更新商品数量
Item& item = _GoodsList[_index[name]];
if (item._price != price)
{
cout << "商品添加失败,价格与记录不符: " << price << endl;
return false;
}
item._cnt += num;
_amount += price * num;
}
else
{
if (price <= 0)
{
cout << "非法单价: " << price << endl;
return false;
}
if (num <= 0)
{
cout << "非法数量: " << num << endl;
return false;
}
if (_capacity < num)
{
printf("容量不足, 容量: %d ,添加的数量: %d\n", _capacity, num);
return false;
}
int sz = _GoodsList.size();
_index[name] = sz;
_GoodsList.push_back(Item(name, price, num));
_amount += price * num;
_capacity -= num;

printf("商品添加成功,商品名: %s,单价: %.2lf,本次添加的数量: %d\n", name.c_str(), price, num);
return true;
}
}

销售货物也是同理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public:
bool SellItem()
{
string name;
int num;
cout << "请输入 [商品名] [数量]" << endl;
cin >> name >> num;
return _SellItem(name, num);
}

private:
bool _SellItem(const string& name,int num)
{
if (num <= 0)
{
cout << "非法的售卖数量: " << num << endl;
return false;
}

if (!_index.count(name))
{
cout << "不存在的商品: " << name << endl;
return false;
}

Item& item = _GoodsList[_index[name]];
if (item._cnt < num)
{
cout << "交易失败,剩余库存不足!剩余: " << item._cnt << " 预期售卖: " << num << endl;
return false;
}

item._cnt -= num;
double sum = num * item._price;
_amount -= sum;
_capacity += num;
_sale += sum;
printf("交易成功!商品名: %s,单价: %.2lf,交易数量: %d,本次交易额: %.2lf\n", name.c_str(), item._price, num, sum);
}

实现多种查询功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public:
void InfoItem()
{
string name;
cout << "请输入待查询的商品名称" << endl;
_InfoItem(name);
}

private:
void _InfoItem(const string& name)
{
if (!_index.count(name))
{
cout << "商品不存在" << endl;
return;
}
Item& item = _GoodsList[_index[name]];
printf("商品名: %s,单价: %.2lf,剩余量: %d", name.c_str(), item._price, item._cnt);
}


下面要根据不同需求排序数组,这里我们就要用sort函数配合lambda表达式方便地使用不同的排序规则进行排序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
public:
void ShowItems()
{
cout << "默认顺序" << endl;
_ShowItems(_GoodsList);
}

void ShowItemsByName(bool reverse_arr=false)//默认升序
{
if (reverse_arr)
{
cout << "按名字降序" << endl;
}
else cout << "按名字升序" << endl;
auto copy = _GoodsList;
sort(copy.begin(), copy.end(), [&](const Item& item1, const Item& item2) {
if (item1._name <= item2._name)return true;
else return false;
});
if (reverse_arr)
{
reverse(copy.begin(), copy.end());
}
_ShowItems(copy);
}

void ShowItemsByPrice(bool reverse_arr = false)//默认升序
{
if (reverse_arr)cout << "按单价降序" << endl;
else cout << "按价格升序" << endl;
auto copy = _GoodsList;
sort(copy.begin(), copy.end(), [&](const Item& item1, const Item& item2) {
if (item1._price <= item2._price)return true;
else return false;
});
if (reverse_arr)
{
reverse(copy.begin(), copy.end());
}
_ShowItems(copy);
}

void ShowItemsByCNT(bool reverse_arr = false)//默认升序
{
if (reverse_arr) cout << "按剩余量降序" << endl;
else cout << "按剩余量升序" << endl;
auto copy = _GoodsList;
sort(copy.begin(), copy.end(), [&](const Item& item1, const Item& item2) {
if (item1._cnt <= item2._cnt)return true;
else return false;
});
if (reverse_arr)
{
reverse(copy.begin(), copy.end());
}
_ShowItems(copy);
}

private:
void _ShowItems(const vector<Item>& goodslist)
{
printf("%-10s %-10s %-4s\n", "商品名", "单价", "剩余数量");
for (auto item : goodslist)
{
printf("%-10s %-10.2lf %-4d\n", item._name.c_str(), item._price, item._cnt);
}
printf("\n");
}
public:

void Info()
{
printf("商品数量: %u ,机器内商品总价值 %.2lf,总销售额: %.2lf,剩余容量: %d\n",
_GoodsList.size(), _amount, _sale, _capacity);
}

实现自动初始化

写一个函数自动初始化参数,方便调试

1
2
3
4
5
6
7
8
9
10
11
12
13
void AutoInit()
{
if (_GoodsList.size() != 0)
{
cout << "不能重复初始化!!!" << endl;
return;
}
_AddItem("小苹果", 5, 10);
_AddItem("大香蕉", 2.5, 2);
_AddItem("香蕉君", 30, 5);
_AddItem("野兽先辈", 1145.14, 15);

}

实现菜单和运行功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public:
void Run()
{

int cmd = 1;
do
{
PrintMenu();
cout << "请输入操作码" << endl;
cin >> cmd;
switch (cmd)
{
case 0:
break;
case 1:
AutoInit(); break;
case 2:
AddItem(); break;
case 3:
ShowItems(); SellItem(); break;
case 4:
Info(); break;
case 5:
ShowItems(); break;
case 6:
ShowItemsByName(); break;
case 7:
ShowItemsByName(true); break;
case 8:
ShowItemsByPrice(); break;
case 9:
ShowItemsByPrice(true); break;
case 10:
ShowItemsByCNT(); break;
case 11:
ShowItemsByCNT(true); break;
default:
cout << "未知操作码" << endl;
break;
}

cout << "输入任意按键继续..." << endl;
getchar();
getchar();

} while (cmd);
}
private:
void PrintMenu()
{
ClearScreen();
printf("===========菜单=============\n");
printf("0.退出 \n1.自动初始化 \n2.添加商品 \n3.购买商品 \n4.显示售货机信息 \n");

cout << "5.默认顺序显示商品列表\n";
cout << "6.按名称升序显示商品列表\n";
cout << "7.按名称降序显示商品列表\n";
cout << "8.按单价升序显示商品列表\n";
cout << "9.按单价降序显示商品列表\n";
cout << "10.按剩余量升序显示商品列表\n";
cout << "11.按剩余量降序显示商品列表\n";

printf("=============================\n\n");
}

void ClearScreen()
{
system("cls");
}

编写main函数

main函数放在main.cpp

其中我们要用到shared_ptr实现共享指针,内部的原理是对同一个指针提供引用计数,当引用计数要归零时才释放资源,达到自动内存管理的目的

1
2
3
4
5
6
7
8
9
#include "VendingMachine.h"

int main()
{
shared_ptr<VendingMachine> pvm(new VendingMachine());

pvm->Run();
return 0;
}

小结

啪的一下很快啊,一个模拟售货机就做出来了。项目很简单,拿来复习,写起来还是很心情愉悦的