在 C++ 中存储数据,如 python 中的字典
Posted
技术标签:
【中文标题】在 C++ 中存储数据,如 python 中的字典【英文标题】:Storig data in C++ like dictionaries in python 【发布时间】:2020-04-26 18:30:59 【问题描述】:我目前正在学习 c++,并且正在制作某种迷你游戏,其中你有村庄,这个村庄的建筑物,建筑物产生资源等。 首先我用 python 制作它,但决定开始用 c++ 制作它。 Python 有字典,对我来说效果很好。例如。
BUILDINGS= 'Sawmill': 'buildingReq': 'wood':10,'iron':10,
'production':'wood':1,
'productionReq':'iron':1,
'upgrade':'Big Sawmil',
'buildingTime':5,
'Smith': ......
然后我有:
class Building():
def __init__(self, buildingtype= '', x = 0, y = 0):
self.buildingReq= constants.BUILDINGS[buildingtype]['buildingReq']
self.production= constants.BUILDINGS[buildingtype]['production']
self.productionReq= constants.BUILDINGS[buildingtype]['productionReq']
def work(self, village):
for key in self.productionReq.keys():
village.resource[key] = village.resource.get(key) - self.productionReq.get(key)
for key in self.production.keys():
village.resource[key] = village.resource.get(key) + self.production.get(key)
在创建对象期间,我具有搜索我想要构建的建筑物及其所有参数的功能。如您所见,这本词典中有不同的类型。在 C++ 中,我必须做 3 张地图,一张用于不同的数据类型集,一张用于构建需求地图(字符串构建,地图(字符串 buildingReq,地图(字符串木 int 10))),一张用于构建时间地图等
现在在 c++ 中我有这样的东西
std::map < std::string, std::map < std::string, std::map < std::string, int>>> buildingInfo=
"Sawmill", "buildingReq", "wood",15,"iron",15, "production", "wood",10,"iron",10,
"Smith", "buildingReq", "wood",10,"iron",10, "production", "wood",10,"iron",10,
"Big Sawmill", "buildingReq", "wood",10,"iron",10, "production", "wood",10,"iron",10,
"Big Smith", "buildingReq", "wood",10,"iron",10, "production", "wood",10,"iron",10
;
std::map <std::string, int> buildingTime=
"Sawmill", 3,
"Smith", 3,
"Big Sawmill", 3,
"Big Smith", 3
;
std::map <std::string, std::string> upgrades=
"Sawmill", "Big Sawmill",
"Smith", "Big Smith"
;
std::map<std::string, int> workersNum=
"Sawmmill", 10,
"Smith", 10
class Building
public:
std::string buildingType;
std::map<std::string, int> production;
std::map<std::string, int> buildingReq;
;
他们通过
提取这些数据 for (auto x : buildingInfo)
if (x.first == buildingType)
for (auto y : x.second)
if (y.first == "buildingReq")
this->buildingReq.insert(y.second.begin(), y.second.end());
if (y.first == "production")
this->production.insert(y.second.begin(), y.second.end());
break;
也许最大的问题不是提取数据,尽管可能是这样,而是以这种方式存储它。在 python 中我有一本字典,但在 c++ 中我有 4 个地图。 我怎么能在 C++ 中做一些类似的事情?还是有更好的方法?
【问题讨论】:
为您的建筑考虑一个真正的类,其中每个字段(需求、生产、升级等)都根据存储在这些字段中的数据类型进行强类型化。 您需要再解释一下您的确切用例,并包含您定义的类的示例。 @nanofarad 我的课堂上有这些字段,我需要的是方便的方式来存储数据和提取有关这些建筑物的数据。在 python 中,我在构造函数 self.buildingReq= constants.BUILDINGS[buildingtype]['buildingReq'] self.production= constants.BUILDINGS[buildingtype]['production'] self.productionReq= constants.BUILDINGS[buildingtype][ 'productionReq'] 你可以拥有持有这些常量的类;它们可以加载到内存中,例如在游戏启动时。除此之外,您的问题还不够清楚,无法提供更详细的见解 别担心,我会看看,看看我能想出什么。乍一看,为什么buildingInfo
不只是一个std::map<std::string, Building>
,每个Building
都包含描述它的数据?我建议从这个问题中退后一步,专注于编写一个好的 Building 类,它具有有用的构造函数、方法等。之后,您可以研究如何有效地使用该类。
【参考方案1】:
编程语言之间的一个很大区别是它们的类型系统有多严格。 Python 的类型系统非常松散,而 C++ 则非常严格。在编写 C++ 时,您应该接受这一点,并在适当的地方创建显式类型。
正如 nanofarad 所提到的,您应该创建一个代表建筑物的 class
。无需使用另一个std::map
来存储建筑物的属性,您只需为它们提供显式成员变量,每个变量都具有该属性的适当类型。下面是它的样子:
class BuildingInfo
public:
std::map<std::string, int> buildingReq;
std::map<std::string, int> production;
std::map<std::string, int> productionReq;
std::string upgrade;
int buildingTime;
;
然后您可以在编译时创建预定义的建筑类型数组,如下所示:
const std::map<std::string, BuildingInfo> buildings =
"Sawmill",
/* buildingReq */ "wood", 15, "iron", 15,
/* production */ "wood", 1,
/* productionReq */ "iron", 1,
/* upgrade */ "Big Sawmill",
/* buildingTime */ 5,
,
"Smith",
...
,
...
;
但是,从性能的角度来看,这并不是最优的。大量内存浪费在映射结构和字符串本身上。例如,每次您必须查找建筑物的要求时,都必须遍历几张地图,从而导致代码相当慢。通过为建筑物和资源提供数字标识符以及使用数组而不是地图,可以使其更加优化。要生成标识符,您可以使用enum
,例如:
enum Building
SAWMILL,
SMITH,
BIG_SAWMILL,
BIG_SMITH,
...
BUILDING_COUNT
;
enum Resource
WOOD,
IRON,
...
RESOURCE_COUNT
;
class BuildingInfo
public:
std::string name;
int buildingReq[RESOURCE_COUNT];
int production[RESOURCE_COUNT];
int productionReq[RESOURCE_COUNT];
BuildingType upgrade;
int buildingTime;
;
const BuildingInfo buildings[BUILDING_COUNT] =
/* name */ "Sawmill",
/* buildingReq */ 15, 15,
/* production */ 1, 0,
/* productionReq */ 0, 1,
/* upgrade */ BIG_SAWMILL,
/* buildingTime */ 5,
,
/* name */ "Smith",
...
,
...
;
但是,后一个示例有点不安全:与enum BuildingType
相比,数组buildings[]
的顺序很容易出错,并且您可能会意外使用来自enum ResourceType
的名称,而您应该使用了一个来自enum BuildingType
。一个折衷方案是使用enum class
而不是enum
来识别建筑和资源类型,并继续使用std::map
而不是数组。然后它看起来像:
enum class Building
SAWMILL,
...,
BIG_SMITH,
;
enum class Resource
WOOD,
IRON,
;
class BuildingInfo
public:
std::map<Resource, int> buildingReq;
std::map<Resource, int> production;
std::map<Resource, int> productionReq;
Building upgrade;
int buildingTime;
;
const std::map<Building, BuildingInfo> buildings =
Building::SAWMILL,
/* buildingReq */ Resource::WOOD, 15, Resource::IRON, 15,
/* production */ Resource::WOOD, 1,
/* productionReq */ Resource::IRON, 1,
/* upgrade */ Building::BIG_SAWMILL,
/* buildingTime */ 5,
,
Building::SMITH,
...
,
...
;
请注意,在上述所有示例中,成员变量buildingReq
、production
和productionReq
的类型相同。明确说明这一点很有意义:
typedef std::map<Resource, int> ResourceCollection;
class BuildingInfo
public:
ResourceCollection buildingReq;
ResourceCollection production;
ResourceCollection productionReq;
...
;
您可以更进一步,将ResourceCollection
转换为正确的class
,具有相互添加和减去资源集合的功能,等等。创建您自己的类型使编译器可以轻松地对您的代码进行类型检查,并在编译时捕获编程错误。
【讨论】:
以上是关于在 C++ 中存储数据,如 python 中的字典的主要内容,如果未能解决你的问题,请参考以下文章