我目前正在为一个游戏引擎开发一个ECS系统,并且偶然发现了一个序列化问题。是我在ECS实现中用于组件存储的数据结构,它是一个预先构造的组件池,这些组件是可回收的。因此,添加一个实体就像为预构造的组件分配值一样简单。系统被设计为使用组件索引,而不是类型,,这就是问题所在。当序列化和反序列化组件时,被视为BaseComponent指针.
组件结构层次化
struct BaseComponent {}; // struct used as base to store components
template<typename T>
struct Component : public BaseComponent {
static const uint_fast32_t ID; // identifier used by the rest of the system
}
struct SomeComponent : public Component<SomeComponent> {
// component specific data
}是组件特定的数据,我想序列化、反序列化并将数据分配给SomeComponent.中的适当字段。
我有一个简单的解决方案,但是当涉及到干净的代码时,它是相当模糊的。我找到的解决方案是将组件内存直接转储到文件中,并通过char缓冲区将其读入内存。然而,这不允许指针,在我看来,这是相当令人厌恶的。我发现的另一个解决方案是,如果可能的话,使用变量函数来构造一个临时的、使用变量展开进行聚合初始化的函数。但是,此方法不解决序列化和反序列化问题,只解决分配问题。
因此,我的问题是:在不知道类型信息的情况下,是否有一种很好的方法来序列化和反序列化多态类型?
发布于 2018-10-22 09:34:51
在这种情况下,我会考虑CRTP模式。基类定义序列化/反序列化函数,这些函数在交付的类中调用实际实现。维基百科的文章有一些很好的例子。
发布于 2018-10-23 14:43:00
首先要做的是:我认为您正在尝试避免这种情况,但无论如何,您都需要为您拥有的每种组件定义一个序列化/反序列化函数。
明白了,你有三个选择。
结构BaseComponent {虚拟std::字符串序列化()= 0;};模板结构组件: public BaseComponent {静态uint_fast32_t ID;虚拟std::字符串序列化(){返回static_cast(this)->serialize();};结构SomeComponent:公共组件{std::字符串序列化(){返回"{a: b,c: d}";};结构OtherComponent:公共组件{std::字符串序列化(){返回"{d: c,b: a}";};{ OtherComponent o1,o2;SomeComponent s1,s2;std::vector组件;components.push_back(&o1);components.push_back(&s1);components.push_back(&o2);components.push_back(&s2);用于(auto* comp : components) { std::cout << comp-> << "\n";}
枚举类ComponentKind { SomeComponent,OtherComponent };结构BaseComponent { ComponentKind类;};模板结构组件:公共BaseComponent {静态const uint_fast32_t ID;};结构SomeComponent: public ComponentKind=:ComponentKind::SomeComponent;} std::string序列化(){返回"{a: c: d}";} };struct OtherComponent: public OtherComponent{ OtherComponent() {OtherComponent(){OtherComponent= ComponentKind::OtherComponent;} std::string OtherComponent(){返回"{d: c,b: a}";};};std::OtherComponent序列化(BaseComponent* comp) {OtherComponent(comp->OtherComponent){ case (ComponentKind::SomeComponent):返回OtherComponentcase (ComponentKind:: OtherComponent ):返回static_cast(comp)->serialize();默认值:“;}{OtherComponent o1,o2;SomeComponent s1,s2;std::vector组件;components.push_back(&o1);components.push_back(&s1);components.push_back(&o2);components.push_back(&s2);for (auto* comp : components) { std::cout <<序列化(Comp) << "\n";}enum类ComponentKind { SomeComponent,OtherComponent };结构BaseComponent { ComponentKind样;};模板结构组件: public BaseComponent { static uint_fast32_t ID;};struct SomeComponent: public Component { SomeComponent() = ComponentKind::SomeComponent;}std::字符串序列化(){返回"{a: b,c: d}";};结构OtherComponent:公共组件{ OtherComponent() {OtherComponent(){OtherComponent()= ComponentKind::OtherComponent;}std::字符串序列化(){返回"{d: c,b}“;} };};字符串序列化(BaseComponent* comp) {开关(comp->种类){ case (ComponentKind:: SomeComponent ):返回static_cast(comp)->serialize();大小写(ComponentKind:: OtherComponent ):返回static_cast(comp)->serialize();默认值:返回“;} void (){OtherComponent o1,o2;SomeComponent s1,s2;std::vector组件;components.push_back(&o1);components.push_back(&s1);components.push_back(&o2);components.push_back(&s2);for (auto* comp : components) {std:cout <<序列化(Comp) << "\n";}}
选项2在BaseComponent上创建一个vtable (动态多态性能开始),并强制您使用虚拟析构函数以确保安全(请查看Scott关于该问题的单词)。
选项3,不需要一个vtable,而是抛出类型安全,并迫使您非常小心的static_casting各地。
我认为人们更喜欢备选方案3而不是2,但老实说,我会考虑第一个方案1。
https://stackoverflow.com/questions/52925664
复制相似问题