2024 年 2 月 15 日 更新
0.设计思路
类视图
- 类内维护一个map对象,map 对象的每一个元素是,key为string ,value为stone*的pair;
- add操作需要3个参数,level、attr、count,有些对象(stone类)包含以上多个参数,因此可以使用函数重载使添加stone方式更加多样;
- sub操作需要2个参数,key 和 count,而 key 这个概念又是由 attr 和 level 共同组成,所以这 2 个参数可以充当 key 使用(定义一个转换函数就很方便啦);
- add 与 sub 操作的具体思路是这样的,如果 map 内存在 key 值相同的 元素(相同的灵石),将元素value中 m_count 增加或减少;不存在 新建(createStone() 将其储存在 堆区),或提示 不存在灵石 无法 消耗;
- 上量两个操作也就利用到了 hasKey(存在这种灵石)和 findKey(返回 对应灵石 在 map 中的迭代器)这2个函数了;
- initStone 的作用是 清空 map 中,所有 m_count(数量)为零的灵石,防止没有意义的输出;
- 而 stonebag 的 << 重载,则是输出 stonebag 中大致的 灵石状况,为了方便,编写了 返回灵石种类 和 返回灵石总数的函数;
- showStones的实现很简单,利用循环依次输出,毕竟 "<<" 的重载已经在每一个灵石类上都实现了,很方便;
- 最后,不要忘了 析构函数 释放所有 申请到的 内存空间,防止 内存泄漏。
1. 错误回顾
- 使用派生手法的类,因为重用代码太多,复制粘贴后,忘记修改,导致逻辑错误;
- 有些算法编写时,因为思绪不畅,导致逻辑错误;
写代码是个慢活,慢慢来吧
2. 目标瞻仰
- 将Stone类封装为抽象类,使代码结构更加清晰(参数添加:string m_name);
- 完善修仙者类,将 灵石包 置入进去,且(设计渡劫,战斗,生死斗等);
- 实现价值类(class ItemValues),将灵石序列(目前想法是vector<Stone*>>)作为返回值,cout输出vPointers(衡量 物品价值 的一种 新的指标);
- 实现物品类(class Item),(有价值的)物品Monster类,将作为子类继承它;
- 实现角色类(class Character),子类有(作为动物的)Monster,修仙者等;
- 思考 ItemMonster 与 ChaMonster 的相互转化
感觉项目越写越多~
3. VS Studying (经验汇总)
- 使用宏定义,可以将一些冗杂的 枚举、类名 进行精简, 提高效率 ,增加可读性(typedef 也可以)
- map erase方法,有时删除内容会访问错误,解决方案:
deleteStone(it++); // 随用随 +, 不用在 for 中递加
- 注意科学编码,劳逸结合,在状态不佳的情况下,编出的代码可能需要全部重写(CC CV 也许可以补救)
思路不对,写什么都没用~
4. 源码展示
StoneBag.h
#pragma once
#include <map>
#include "DeriveStone.h"
#include "AttributeStone.h"
#define _map map<string, SpriteStone*>
#define _it map<string, SpriteStone*>::iterator
using std::map;
using std::pair;
using std::make_pair;
class StoneBag{
public:
// creates //
~StoneBag();
// values //
int getKinds() const;
int getAllNums() const;
_Key getKey(_Level level,
_Attr attr = _Attr::NONE);
bool hasKey(_Key key);
_it findKey(_Key key);
// actions //
void initStones();
_pSto createStone(_Level level,
int count = 1,
_Attr attr = _Attr::NONE) const;
void deleteStone(_it it);
void addStone(_cSto_ s);
void addStone( _Level level,
int count = 1,
_Attr attr = _Attr::NONE);
void subStone(_Key key,
int count = 1);
void subStone(_Level level,
int count = 1,
_Attr attr = _Attr::NONE);
void showStones() const;
// friends //
friend ostream& operator<<(ostream& cout,
const StoneBag& sbag);
protected:
map<string, _pSto> m_stones;
};
ostream& operator<<(ostream& cout,
const StoneBag& sbag);
StoneBag.cpp
#include "StoneBag.h"
StoneBag::~StoneBag(){
// cout << "销毁 灵石包" << endl;
for (auto it = m_stones.begin();
it != m_stones.end();)
deleteStone(it++);
}
int StoneBag::getKinds() const{
return (int) m_stones.size();
}
int StoneBag::getAllNums() const{
int sum = 0;
for (auto it = m_stones.begin();
it != m_stones.end();
it++)
sum += it->second->count();
return sum;
}
string StoneBag::getKey(_Level level
, _Attr attr){
return getStoneName(level, attr);
}
bool StoneBag::hasKey(_Key key){
for (auto it = this->m_stones.begin();
it != this->m_stones.end();
it++)
if (it->first == key)
return true;
return false;
}
_it StoneBag::findKey(_Key key){
for (auto it = this->m_stones.begin();
it != this->m_stones.end();
it++)
if (it->first == key)
return it;
return m_stones.end();
}
void StoneBag::initStones()
{
for (auto it = m_stones.begin();
it != m_stones.end();)
if (it->second->count() == 0)
deleteStone(it++);
else it++;
}
_pSto StoneBag::createStone(_Level level,
int count, _Attr attr) const{
SpriteStone* pstone = nullptr;
switch (level){
case _Level::PRIMARY_LEVEL:
pstone = new PrimaryStone(count);
break;
case _Level::MIDDLE_LEVEL:
pstone = new MiddleStone(count);
break;
case _Level::ADVANCE_LEVEL:
pstone = new AdvanceStone(count);
break;
case _Level::MONSTER_LEVLE:
pstone = new MonsterStone(count);
break;
case _Level::ATTRIBUTE_LEVEL:
pstone = new AttributeStone(count, attr);
break;
default:
break;
return nullptr;
} return pstone;
}
void StoneBag::deleteStone(_it it){
if (it->second != NULL){
delete it->second;
it->second = NULL;
} m_stones.erase(it);
}
void StoneBag::addStone(_cSto_ s){
_Level level = s.level();
_Attr attr = s.attr();
string key = getKey(level, attr);
if (this->hasKey(key)){
auto it = findKey(key);
it->second->addCount(s.count());
cout << "灵石包:"
<< " 添加灵石 " << s.str()
<< " 共计: "
<<it->second->str()
<< endl;
} else {
_pSto pstone =
createStone(level, s.count(), s.attr());
m_stones.insert(make_pair(key, pstone));
cout << "灵石包:"
<<" 新增灵石 "
<< (*pstone)
<< endl;
}
}
void StoneBag::addStone(_Level level,
int count, _Attr attr){
string key = getKey(level, attr);
if (this->hasKey(key)){
auto it = findKey(key);
_Key stoneName =
getStoneName(level, attr) + " ";
it->second->addCount(count);
cout << "灵石包:"
<< " 添加灵石 " << stoneName
<< count << " 枚 "
<< " 共计: "
<< it->second->str()
<< endl;
} else {
_pSto pstone =
createStone(level, count, attr);
m_stones.insert(make_pair(key, pstone));
cout << "灵石包:"
<< " 新增灵石 "
<< (*pstone)
<< endl;
}
}
void StoneBag::subStone(_Key key, int count){
if (!hasKey(key))
cout << "消耗灵石: 灵石包 内 没有指定灵石哦"
<< endl;
else{
auto it = findKey(key);
int m_count = it->second->count();
if (m_count < count){
cout << "消耗灵石: 灵石包 内 没有足够灵石哦"
<< endl;
return;
}
it->second->addCount(-count);
cout << "消耗灵石: "
<< key + " " << -count << " 枚 "
<< "剩余: " << *(it->second)
<< endl;
} initStones();
}
void StoneBag::subStone(_Level level,
int count, _Attr attr){
_Key key = getKey(level, attr);
subStone(key, count);
}
void StoneBag::showStones() const{
cout << "------ 灵石包 ------" << endl;
for (auto it = m_stones.begin();
it != m_stones.end();
it++){
cout << " - ";
cout << *(it->second) << endl;
} cout << string(20, '-') << endl;
}
ostream& operator<<(ostream& cout,
const StoneBag& sbag){
int kinds = sbag.getKinds();
int allNums = sbag.getAllNums();
cout << kinds << " 种 灵石 共计: "
<< allNums << " 枚";
// TODO: 在此处插入 return 语句
return cout;
}
main.cpp
#include "StoneBag.h"
using namespace std;
void addStone(StoneBag& sbag, const SpriteStone& stone)
{
_Key key = getStoneName(stone);
cout << "------ 添加:" << key << " -----" << endl;
sbag.addStone(stone);
sbag.addStone(stone);
sbag.addStone(stone);
cout << "------ 消耗:" << key << " -----" << endl;
sbag.subStone(key);
sbag.subStone(key, 999);
}
void testStoneBag()
{
cout << "灵石包测试:" << endl;
cout << string(48, '-') << endl;
StoneBag sbag;
AttributeStone mstone(10, StoneAttr::METAL);
AttributeStone wstone(10, StoneAttr::WOOD);
AttributeStone wastone(10, StoneAttr::WATER);
AttributeStone fstone(10, StoneAttr::FIRE);
AttributeStone estone(10, StoneAttr::EARTH);
PrimaryStone ps(10);
MiddleStone ms(102);
AdvanceStone as(933);
MonsterStone mos(32);
addStone(sbag, mstone);
addStone(sbag, wstone);
addStone(sbag, wastone);
addStone(sbag, fstone);
addStone(sbag, estone);
addStone(sbag, ps);
addStone(sbag, ms);
addStone(sbag, as);
addStone(sbag, mos);
sbag.addStone(SpriteStoneLevel::MIDDLE_LEVEL, 100);
sbag.addStone(_Level::ATTRIBUTE_LEVEL, 100, _Attr::EARTH);
sbag.subStone("中品灵石", 10);
sbag.subStone("火灵石", 30);
sbag.subStone(_Level::MIDDLE_LEVEL, 100);
sbag.showStones();
cout << sbag << endl;
cout << endl;
}
int main(void)
{
testStoneBag();
system("pause");
return 0;
}