C++ 将字符串映射到对象
C++ map string to object
我正在尝试创建一个 class 可以将字符串映射到一些任意对象甚至原始类型。澄清一下,我不是在谈论一种单一的泛型类型,而是不同的类型,所以地图可能看起来像这样:
["speed": 3, "useNormal": false, "normal": Vec3()]
我尝试过的一种方法是创建一个 BaseObject
结构并从中派生其他 class,例如 IntObject
和 FloatObject
。这样我就能够创建一个 std::map<std::string, BaseObject*>
。但是这种方法感觉很笨重,地图的 getter 和 setter 需要为每种类型都有一个 switch case。
有人建议使用字节。基本上这意味着将对象序列化和反序列化为字节数组,因此映射看起来像这样 std::map<std::string, byte*>
。但是使用这种方法要克服的最大障碍是以某种方式从字节数组生成特定类型的对象,我不知道该怎么做。
另一个建议也是使用 c++17 变体。但这太新了,无法得到广泛支持。
如有任何意见,我将不胜感激!
普遍认为 std::map<std::string, std::any>>
是解决此问题的最佳方案。但是由于我试图避免使用 boost 和 c++17,这里是一个纯 c++ 实现,一个面向对象的方法来解决这个问题:
struct SuperObject {};
template<class T>
struct BaseObject: SuperObject {
T _value;
BaseObject(T value) : _value(value) {}
};
std::unordered_map<std::string, SuperObject*> objectMap;
template<typename T>
void setValue(std::string name, T value) {
objectMap[name] = new BaseObject<T>(value);
}
template <typename T>
T getValue(const std::string& name) {
return ((BaseObject<T>*)(objectMap[name]))->_value;
}
请注意调用时的巨大内存泄漏setValue()
使用智能指针而不是原始指针可以修复内存泄漏。这是@Haeri
的修改版本
#include <iostream>
#include <memory>
#include <unordered_map>
struct SuperObject {};
template<class T>
struct BaseObject : SuperObject {
T _value;
BaseObject(T value) : _value(value) {
std::cout << "Constructed" << std::endl;
}
~BaseObject() {
std::cout << "Destroyed" << std::endl;
}
};
std::unordered_map<std::string, std::shared_ptr<SuperObject>> objectMap;
template<typename T>
void setValue(std::string name, T value) {
objectMap[name] = std::make_shared< BaseObject<T>>(value);
}
template <typename T>
T getValue(const std::string& name) {
return ((std::static_pointer_cast<BaseObject<T>>)(objectMap[name]))->_value;
}
int main()
{
setValue<int>("a", 5);
setValue<double>("b", 5.62342423);
std::cout << getValue<int>("a") << std::endl;
std::cout << getValue<double>("b") << std::endl;
}
我正在尝试创建一个 class 可以将字符串映射到一些任意对象甚至原始类型。澄清一下,我不是在谈论一种单一的泛型类型,而是不同的类型,所以地图可能看起来像这样:
["speed": 3, "useNormal": false, "normal": Vec3()]
我尝试过的一种方法是创建一个 BaseObject
结构并从中派生其他 class,例如 IntObject
和 FloatObject
。这样我就能够创建一个 std::map<std::string, BaseObject*>
。但是这种方法感觉很笨重,地图的 getter 和 setter 需要为每种类型都有一个 switch case。
有人建议使用字节。基本上这意味着将对象序列化和反序列化为字节数组,因此映射看起来像这样 std::map<std::string, byte*>
。但是使用这种方法要克服的最大障碍是以某种方式从字节数组生成特定类型的对象,我不知道该怎么做。
另一个建议也是使用 c++17 变体。但这太新了,无法得到广泛支持。
如有任何意见,我将不胜感激!
普遍认为 std::map<std::string, std::any>>
是解决此问题的最佳方案。但是由于我试图避免使用 boost 和 c++17,这里是一个纯 c++ 实现,一个面向对象的方法来解决这个问题:
struct SuperObject {};
template<class T>
struct BaseObject: SuperObject {
T _value;
BaseObject(T value) : _value(value) {}
};
std::unordered_map<std::string, SuperObject*> objectMap;
template<typename T>
void setValue(std::string name, T value) {
objectMap[name] = new BaseObject<T>(value);
}
template <typename T>
T getValue(const std::string& name) {
return ((BaseObject<T>*)(objectMap[name]))->_value;
}
请注意调用时的巨大内存泄漏setValue()
使用智能指针而不是原始指针可以修复内存泄漏。这是@Haeri
的修改版本#include <iostream>
#include <memory>
#include <unordered_map>
struct SuperObject {};
template<class T>
struct BaseObject : SuperObject {
T _value;
BaseObject(T value) : _value(value) {
std::cout << "Constructed" << std::endl;
}
~BaseObject() {
std::cout << "Destroyed" << std::endl;
}
};
std::unordered_map<std::string, std::shared_ptr<SuperObject>> objectMap;
template<typename T>
void setValue(std::string name, T value) {
objectMap[name] = std::make_shared< BaseObject<T>>(value);
}
template <typename T>
T getValue(const std::string& name) {
return ((std::static_pointer_cast<BaseObject<T>>)(objectMap[name]))->_value;
}
int main()
{
setValue<int>("a", 5);
setValue<double>("b", 5.62342423);
std::cout << getValue<int>("a") << std::endl;
std::cout << getValue<double>("b") << std::endl;
}