C++:如何在不使用库的情况下序列化/反序列化对象
C++: how to serialize/deserialize objects without the use of libraries?
我正在努力了解在不使用库的情况下,序列化/反序列化是如何在C++中工作的。我从简单的对象开始,但当反序列化一个向量时,我发现,如果不先写它的大小,我就无法获得向量。此外,我不知道我应该选择哪种文件格式,因为,如果数字存在于矢量大小之前,我就无法正确读取。此外,我想用类和映射容器来实现这一点。我的任务是序列化/反序列化这样的对象:
PersonInfo
{
unsigned int age_;
string name_;
enum { undef, man, woman } sex_;
}
Person : PersonInfo
{
vector<Person> children_;
map<string, PersonInfo> addrBook_;
}
目前我知道如何序列化像这样的简单对象:
vector<PersonInfo> vecPersonInfo;
vecPersonInfo.push_back(*personInfo);
vecPersonInfo.push_back(*oneMorePersonInfo);
ofstream file("file", ios::out | ios::binary);
if (!file) {
cout<<"can not open file";
} else {
vector<PersonInfo>::const_iterator iterator = vecPersonInfo.begin();
for (; iterator != vecPersonInfo.end(); iterator++) {
file<<*iterator;
}
你能建议我如何为这个复杂的对象做到这一点吗?或者一个很好的教程来清楚地解释它?
一种模式是实现一个抽象类,该类定义用于序列化的函数,并且该类定义进入序列化程序的内容和输出的内容。例如:
class Serializable
{
public:
Serializable(){}
virtual ~Serializable(){}
virtual void serialize(std::ostream& stream) = 0;
virtual void deserialize(std::istream& stream) = 0;
};
然后为要序列化的类/结构实现Serializable接口:
struct PersonInfo : public Serializable // Yes! It's possible
{
unsigned int age_;
string name_;
enum { undef, man, woman } sex_;
virtual void serialize(std::ostream& stream)
{
// Serialization code
stream << age_ << name_ << sex_;
}
virtual void deserialize(std::istream& stream)
{
// Deserialization code
stream >> age_ >> name_ >> sex_;
}
};
休息吧,我相信你知道。不过,以下是一些需要克服的障碍,可以在业余时间完成:
- 当您向流中写入一个包含空格的字符串并尝试将其读回时,您将只得到其中的一部分,而字符串的其余部分会"破坏"此后读取的值
- 如何对其进行编程,使其跨平台(little-endian与big-endian)
- 程序如何自动检测,在反序列化时要创建哪个类
线索:
- 使用具有编写bool、int、float、字符串等函数的自定义序列化程序
- 使用字符串表示正在序列化的对象类型,并在反序列化时使用factory创建该对象的实例
- 使用预定义的宏来确定正在编译代码的平台
- 总是以固定的端序写入文件,并使使用其他端序的平台适应这种情况
最基本的形式是定义一个"可串行化"接口(抽象类),用于定义虚拟读/写方法。您还定义了一个"Stream"接口,该接口为基本基元类型(例如,读取/写入int、float、字节、字符、查找/重置)提供了一个通用的API,也可能为一些在流上操作的复合类型(例如字符串、向量等的值数组)提供了通用的API。如果适合您,您可以使用C++IOStreams。
您还需要为工厂提供一些id系统,以便在加载/取消序列化时创建相应的类,并在序列化复杂类型时进行引用,以便在必要时使用适当的结构/长度信息标记/标头每个逻辑部分。
然后,您可以为每个介质创建具体的流类(如文本文件、二进制文件、内存中、网络等)。
然后,每个想要序列化的类都必须继承serializable接口并实现细节(如果是复合/复杂类,则递归地利用为其他类型定义的可序列化接口)。
当然,这是一种天真且"侵入性"的添加序列化的方式(必须修改参与类)。然后,您可以使用模板或预处理器技巧来减少它的侵入性。请参阅Boost或协议缓冲区,或任何其他库,了解代码中的想法。
你真的确定要自己滚吗?它可能会变得非常混乱,尤其是当你有指针,对象之间的指针(包括循环)时,你还需要在当前运行的加载/取消序列化正确之前的某个时刻修复/转换这些指针。
- 如何在不知道属性具有哪些构造函数的情况下初始化属性?
- 在没有库的情况下初始化 OpenGL
- 在没有构造函数的情况下初始化 const c++ 类
- 默认情况下初始化时 POD 是否给予特殊处理 (C++14)?
- 为什么默认情况下初始化局部变量
- 有没有一种方法可以在不使用std ::移动的情况下初始化类构建类的类
- 如果在没有 new 运算符的情况下初始化,C++是否将类对象视为值类型
- 如何在没有循环的情况下初始化 std::vector
- 如何在不使用指针的情况下初始化具有可变大小的 2D 数组
- 如何在给定包含类的实例的情况下实例化嵌套类
- 在不使用"new"的情况下实例化参数参数中的对象
- 如何在不存在任何数据损坏风险的情况下序列化对象
- 在不使用动态数组的情况下初始化数组时出现问题
- 为什么无法使用复制构造函数实例化"non const"而可以在没有复制构造函数的情况下实例化配对?
- C++:如何在不使用库的情况下序列化/反序列化对象
- 在没有“new”关键字的情况下实例化类会导致在堆栈或堆上创建其内部变量
- 如何在没有初始化对象的情况下初始化对象的管理器shared_ptr?
- 如何在不模板化类的情况下模板化成员变量
- 在没有 new 关键字的情况下初始化C++对象的内存从何而来
- 如何在构造函数外部分配 Boost 的情况下序列化大型错误定位浮点数组?