将类型保存到文件
Save a Type to a file
我正在尝试制作一个关卡加载系统,其中关卡文件存储为一些二进制文件,其中包含要生成的对象的 class 及其位置和比例。我无法弄清楚的一件事是如何将 class 类型转换为可以写入二进制文件并稍后检索的类型。
我尝试将其转换为字符串,但如何将 typeid(type).name() 转回 class 类型以生成?
接受任何执行此操作的方法
I tried converting it to a string, but then how do I turn that
typeid(type).name() back into the class type to spawn?
你必须以某种方式自己制作它(因为语言中没有任何东西可以 "go the other way" 可以这么说,那就是从 typeid 构造一个对象),例如。使用 switch
语句(或 if/else 结构),ala:
switch (my_type_id) {
//... add cases here for the types you need
}
使用 typeid 的问题是它不是持久的。因此,建议您构建自己的 list/enum 所需类型。
如果你不是在制作自己的 ID/enum 类型并且想使用 typeid,我建议你使用 boost typeindex 而不是 https://www.boost.org/doc/libs/1_59_0/doc/html/boost_typeindex.html,那可能会省去一些意外调试。最简单的可能仍然是为您需要的类型制作自己的枚举。
对于更高级的解决方案,您甚至可以查看 boost serialize library。
这里发生了一些事情,所以我冒昧地写了一个简短的片段。
当您不知道它们的类型时,为了将一堆 objects 读入像下面这样的单个容器中,它们都需要从基数 class 派生。或者,您可以传递 deserialize
函数不同的向量(或其他容器)来存储不同的类型。什么都行。
deserialize
函数然后使用 switch
就像@darune 建议的那样构造适当的类型。
有各种各样的序列化/反序列化库,它们可以让您比这更复杂,并存储更复杂的 objects 组。我经常使用 rapidjson for this sort of thing. boost.serialize 是另一种选择(同样是@darune 建议的)。
#include <fstream>
#include <iostream>
#include <vector>
using std::ifstream;
using std::vector;
using std::cout;
using std::endl;
class Object
{
public:
double position;
double scale;
Object(const double& position, const double& scale)
: position(position), scale(scale) { }
virtual ~Object() {}
};
class Foo : public Object
{
public:
static const int id = 0;
Foo(const double& position, const double& scale)
: Object(position, scale) { }
};
class Bar : public Object
{
public:
static const int id = 1;
Bar(const double& position, const double& scale)
: Object(position, scale) { }
};
Object* deserialize(int id, const double& position, const double& scale)
{
switch (id)
{
case Foo::id:
return new Foo(position, scale);
case Bar::id:
return new Bar(position, scale);
default:
return nullptr;
};
}
然后一个从文本文件中读入的示例如下所示
int main(void)
{
vector<Object*> objects;
ifstream fin;
fin.open("objects.txt");
if (!fin)
throw std::runtime_error("Unable to open file");
// Read in the id, position and scale from a file
int id;
double position, scale;
while (!fin.eof())
{
fin >> id >> position >> scale;
Object* object = deserialize(id, position, scale);
if (object != nullptr)
objects.push_back(object);
}
fin.close();
// Print out the objects
for (auto pobj: objects)
cout << pobj->position << " " << pobj->scale << endl;
// Don't forget to clean up
for (auto object: objects)
delete object;
}
在这种情况下,objects.txt 是一个仅以空格分隔的文本文件 id position scale
(没有 header)。例如
1 0.4 10
0 0.1 5
0 0.1 1
从二进制读入是类似的。
我正在尝试制作一个关卡加载系统,其中关卡文件存储为一些二进制文件,其中包含要生成的对象的 class 及其位置和比例。我无法弄清楚的一件事是如何将 class 类型转换为可以写入二进制文件并稍后检索的类型。
我尝试将其转换为字符串,但如何将 typeid(type).name() 转回 class 类型以生成?
接受任何执行此操作的方法
I tried converting it to a string, but then how do I turn that typeid(type).name() back into the class type to spawn?
你必须以某种方式自己制作它(因为语言中没有任何东西可以 "go the other way" 可以这么说,那就是从 typeid 构造一个对象),例如。使用 switch
语句(或 if/else 结构),ala:
switch (my_type_id) {
//... add cases here for the types you need
}
使用 typeid 的问题是它不是持久的。因此,建议您构建自己的 list/enum 所需类型。
如果你不是在制作自己的 ID/enum 类型并且想使用 typeid,我建议你使用 boost typeindex 而不是 https://www.boost.org/doc/libs/1_59_0/doc/html/boost_typeindex.html,那可能会省去一些意外调试。最简单的可能仍然是为您需要的类型制作自己的枚举。
对于更高级的解决方案,您甚至可以查看 boost serialize library。
这里发生了一些事情,所以我冒昧地写了一个简短的片段。
当您不知道它们的类型时,为了将一堆 objects 读入像下面这样的单个容器中,它们都需要从基数 class 派生。或者,您可以传递 deserialize
函数不同的向量(或其他容器)来存储不同的类型。什么都行。
deserialize
函数然后使用 switch
就像@darune 建议的那样构造适当的类型。
有各种各样的序列化/反序列化库,它们可以让您比这更复杂,并存储更复杂的 objects 组。我经常使用 rapidjson for this sort of thing. boost.serialize 是另一种选择(同样是@darune 建议的)。
#include <fstream>
#include <iostream>
#include <vector>
using std::ifstream;
using std::vector;
using std::cout;
using std::endl;
class Object
{
public:
double position;
double scale;
Object(const double& position, const double& scale)
: position(position), scale(scale) { }
virtual ~Object() {}
};
class Foo : public Object
{
public:
static const int id = 0;
Foo(const double& position, const double& scale)
: Object(position, scale) { }
};
class Bar : public Object
{
public:
static const int id = 1;
Bar(const double& position, const double& scale)
: Object(position, scale) { }
};
Object* deserialize(int id, const double& position, const double& scale)
{
switch (id)
{
case Foo::id:
return new Foo(position, scale);
case Bar::id:
return new Bar(position, scale);
default:
return nullptr;
};
}
然后一个从文本文件中读入的示例如下所示
int main(void)
{
vector<Object*> objects;
ifstream fin;
fin.open("objects.txt");
if (!fin)
throw std::runtime_error("Unable to open file");
// Read in the id, position and scale from a file
int id;
double position, scale;
while (!fin.eof())
{
fin >> id >> position >> scale;
Object* object = deserialize(id, position, scale);
if (object != nullptr)
objects.push_back(object);
}
fin.close();
// Print out the objects
for (auto pobj: objects)
cout << pobj->position << " " << pobj->scale << endl;
// Don't forget to clean up
for (auto object: objects)
delete object;
}
在这种情况下,objects.txt 是一个仅以空格分隔的文本文件 id position scale
(没有 header)。例如
1 0.4 10
0 0.1 5
0 0.1 1
从二进制读入是类似的。