想象这样一个场景,我们有一个表结构体StudentInfo,同时用数组存储它作为一张表,我们需要提供一套根据Key来增删改查的函数操作这张表。
(这里可能有聪明的小伙伴会想到为什么不用哈希表来存储,这样不就自带一套根据Key来增删改查函数了吗?
是的一般情况下可以这样,但也有些情景下不能使用哈希表,比如UE中TSet不支持同步。)
但如果每有一张这样的表我们都要写一套增删改查函数未免太累了。
我们仔细观察增删改查函数时会发现,除了操作的表,key不同外,代码结构上是相同的,那怎么让表和函数结构解耦呢?
因为表可能是私有成员同时还需要用到表的key,所以用模板还不太好解决。
可以考虑用宏来做。
比如在某个模块中有多张表:
struct StudentInfo{
int Id;
std::string Val1;
float Val2;
};
struct Fish{
//...
}
//...
class Module{
//...
private:
//SaveGame
std::vector<StudentInfo> StudentInfoTable;
std::vector<FishInfo> FishInfoTable;
//其他表...
public:
//各表的增删改查函数...
}
比如我们想为所有表提供一个Has函数,可以写个宏:
(如果对##的作用不了解可以点击看这篇文章)
#define DECLARE\_DATA\_TABLE\_HAS\_METHOD(DataArray, KeyType, KeyField) \
bool DataArray##HasKey(KeyType FindBy##KeyField){ \
bool IsHas = false; \
for(const auto &Row : DataArray){ \
if(Row.KeyField == FindBy##KeyField){ \
IsHas = true; \
break; \
} \
} \
return IsHas; \
} \
(这里不讨论实现性能问题,那不是这篇文章的主题)
然后可以在需要定义has函数的模块中加上这个宏传入表和key信息就等于生成了一个该表的Has函数:
DECLARE\_DATA\_TABLE\_CRUD\_METHOD(StudentInfoTable, StudentInfo, int, Id)
等价于
bool StudentInfoTableHasKey(KeyType FindById){
//...
}
接下来就可以举一反三写出生成其它函数的宏,同时我们还可以写个宏来专门负责打包这些宏:
//生成数据表基础的增删改查方法
#define DECLARE\_DATA\_TABLE\_CRUD\_METHOD(DataArray, RowType, KeyType, KeyField) \
DECLARE\_DATA\_TABLE\_HAS\_METHOD(DataArray, KeyType, KeyField)\
DECLARE\_DATA\_TABLE\_FIND\_METHOD(DataArray, RowType, KeyType, KeyField)\
DECLARE\_DATA\_TABLE\_FIND\_OR\_ADD\_METHOD(DataArray, RowType, KeyType, KeyField)\
//...
这样我们为每张表写增删改查函数就只需要一条宏:
DECLARE\_DATA\_TABLE\_CRUD\_METHOD(StudentInfoTable, StudentInfo, int, Id)
这个例子只是用来理解思路。
**完整样例代码**:
#include<iostream>
#include<string>
#include<vector>
#define DECLARE\_DATA\_TABLE\_HAS\_METHOD(DataArray, KeyType, KeyField) \
bool DataArray##HasKey(KeyType FindBy##KeyField){ \
bool IsHas = false; \
for(const auto &Row : DataArray){ \
if(Row.KeyField == FindBy##KeyField){ \
IsHas = true; \
break; \
} \
} \
return IsHas; \
} \
#define DECLARE\_DATA\_TABLE\_FIND\_METHOD(DataArray, RowType, KeyType, KeyField)\
RowType \*DataArray##FindRow(KeyType FindBy##KeyField){\
RowType \*Ret = nullptr;\
for(auto &Row : DataArray){\
if(Row.KeyField == FindBy##KeyField){\
Ret = &Row;\
break;\
}\
}\
return Ret;\
}\
//前置依赖:Find
#define DECLARE\_DATA\_TABLE\_FIND\_OR\_ADD\_METHOD(DataArray, RowType, KeyType, KeyField) \
RowType &DataArray##FindOrAddRow(KeyType In##KeyField){\
RowType \*FindRow = DataArray##FindRow(In##KeyField);\
if(FindRow == nullptr){\
RowType Row;\
Row.KeyField = In##KeyField;\
DataArray.push\_back(Row);\
FindRow = &DataArray[DataArray.size()-1];\
}\
return \*FindRow;\
}\
//生成数据表基础的增删改查方法
#define DECLARE\_DATA\_TABLE\_CRUD\_METHOD(DataArray, RowType, KeyType, KeyField) \
DECLARE\_DATA\_TABLE\_HAS\_METHOD(DataArray, KeyType, KeyField)\
DECLARE\_DATA\_TABLE\_FIND\_METHOD(DataArray, RowType, KeyType, KeyField)\
DECLARE\_DATA\_TABLE\_FIND\_OR\_ADD\_METHOD(DataArray, RowType, KeyType, KeyField)\
struct StudentInfo{
int Id;
std::string Val1;
float Val2;
};
class Module{
//...
private:
//SaveGame
std::vector<StudentInfo> StudentInfoTable;
public:
DECLARE\_DATA\_TABLE\_CRUD\_METHOD(StudentInfoTable, StudentInfo, int, Id)
/\*
DECLARE\_DATA\_TABLE\_HAS\_METHOD(StudentInfoTable, int, Id);
DECLARE\_DATA\_TABLE\_FIND\_METHOD(StudentInfoTable, StudentInfo, int, Id);
DECLARE\_DATA\_TABLE\_FIND\_OR\_ADD\_METHOD(StudentInfoTable, StudentInfo, int, Id);
\*/
};
int main(){
Module NewModule;
std::cout << NewModule.StudentInfoTableHasKey(5) << "\n";
std::cout << NewModule.StudentInfoTableFindRow(5) << "\n";
StudentInfo &FindStudentInfo = NewModule.StudentInfoTableFindOrAddRow(2001);
FindStudentInfo.Val1 = "zsd";
FindStudentInfo.Val2 = 1.5f;
std::cout << NewModule.StudentInfoTableFindOrAddRow(2001).Val2 << "\n";
return 0;
}
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。