C++语言的序列化指南

453 阅读8分钟

序列化将一个对象转换为字节流,以存储在磁盘中或通过网络发送给另一台计算机。在C++中,有两种对象:基本对象和从定义的类中实例化的对象。注意,在C++中,结构体被认为是一个类,而结构体的名称代表结构体的实例化对象。

单个基本对象通常不被序列化。然而,由于实例化的对象有基本对象,随着整个对象被序列化,基本对象也被序列化。在C++中,所有的数据结构,如向量,都是预定义的类。

序列化也被称为marshaling。与序列化相反的是反序列化或解串联。从磁盘或网络上作为文件的序列化对象可以在本地计算机上转换回(复活)为对象,以便与本地C++应用程序(程序)一起使用。

这篇文章指导你更好地理解C++序列化库以及如何编写你自己的序列化库。它的重点是序列化的标准流,JSON--见下文。

文章内容

二进制和文本流

二进制
一个编译过的C++程序被说成是二进制形式。一个序列化的流可以是二进制形式的。然而,本文将不考虑二进制的序列化对象。

文本
串行化的流可以是文本形式的。今天使用的两个文本标准是JSON和XML。理解和处理JSON比理解和处理XML要容易。所以本文中使用JSON。

主要目标


序列化的主要目标是,序列化的流应该是向后兼容和向前兼容的。它还应该可以在不同的操作系统和不同的计算机结构中使用。

版本
假设你写了一个程序,并把它交给了客户,客户也很满意。这很好。后来,客户需要修改。然而,今天,客户雇用了他自己的程序员。这位程序员要求你为一个类增加另一个属性(数据成员),并通过网络发送相应的目标。他打算将该对象装入程序;当你这样做时,序列化的流必须向后兼容旧对象。

C++和其他语言的规范随着时间的推移而改变。在一些规范中,你会被告知将在下一个和未来的规范中发生的一些变化。通常不可能告知你所有将发生的变化。所以,只要涉及到这些未来的新变化,你的序列化流应该是向前兼容的。前向兼容有其局限性,因为不是所有的未来变化都能被确定。

前向和后向兼容性都是由称为版本控制的方案来处理的。

JSON流

JSON是JavaScript Object Notation的缩写。

JSON是一种用于存储和传输数据的文本格式。

JSON是 "自我描述的"。

JSON也是一个古老的标准,所以它很适合C++文本序列化和反序列化。因此,要发送一个C++实例化的对象,将其转换为JSON对象并发送。就在JSON对象被发送之前,它被称为一个流。当JSON对象在其序列中被接收时,它仍然被称为一个流,用于反序列化。

JSON 语法


对于JSON,一个数据点是一个键/值对。例如,在

    "name":"Smith"

name是一个键,而Smith是值。一个对象是由大括号限定的,如:。

    {"name" : "Smith", "height" : 1.7}

数据由逗号分隔。任何文本,无论它是键还是值,都必须用双引号。数字的书写没有引号。

数组以方括号为界,如:

    ["orange", "banana", "pear", "lemon"]

在下面的代码中,有一个数据点的值是一个数组,用arr标识。

    {"arr" : [`"orange", "banana", "pear", "lemon"]}

注意:对象可以在JSON中嵌套,有了它,对象就可以被识别。

JSON数据值


可能的JSON数据值是。

  • 一个字符串
  • 一个数字
  • 一个对象
  • 一个数组
  • 一个布尔值
  • 一个函数(但要用双引号)。

一个C++日期或任何其他不在此列表中的对象必须转换为字面字符串才能成为一个JSON值。

比较C++和JSON对象

下面是一个简单的C++程序,有一个简单的对象,默认的构造函数。

#include
using namespace std;

class TheCla
    {
        public:
        int num;

        int mthd (int it)
            {
                return it;
            }
    };

int main()
    {
        TheCla obj;
        int no = obj.mthd(3);
        cout << no << endl;

        return 0;
    }

相当于JSON对象的内容如下。

    {"obj": {"num" : null, "mthd" : "int mthd (int it) { return it;}"}}

根据定义,一个JSON对象是序列化的。

请注意对象的名称是如何被指出的。另外,请注意函数的名称是如何被指出的。在接收端,负责反序列化的C++程序必须将其转换为C++类和对象,然后进行编译。该程序还必须识别字符串形式的函数,去掉双引号,并在编译前将函数作为文本。

为了方便,应该发送元数据。元数据是关于数据的数据。一个带有元数据的C++地图可以被发送。地图本身是一个C++对象,它将不得不被转换为JSON对象。它将被发送,后面是感兴趣的JSON对象。

JSON对象是一个流对象。在它被准备好后,它应该被发送到C++ ostream对象,以保存为文件或通过网络发送。在接收计算机上,C++ istream将接收该序列。然后它将被反序列化程序带走,该程序将以C++格式重现该对象。 ostream和istream是C++ fstream的对象。

注意:在JavaScript(ECMAScript)中,序列化被称为,字符串化,反序列化被称为解析化。

JSON对象和JavaScript对象

JSON对象和JavaScript对象是相似的。JavaScript对象比JSON对象有更少的限制。JSON对象是由JavaScript对象设计的,但今天,它可以被许多其他计算机语言使用。JSON是最常见的存档(序列化的序列),用于在网络服务器和他们的客户之间发送数据。C++库使用JSON,但没有一个库能满足为C++制作档案的大部分目标。

注意:在JavaScript中,一个函数不是一个字符串。任何以字符串形式接收的函数都会被转换为正常语法的函数。

要知道的更多

除了了解上述内容外,为了给自己制作一个序列化或反序列化库,你还必须知道。

  • 如何用JSON格式来表达C++指针到对象。
  • 如何用JSON格式来表达C++的继承性。
  • 如何用JSON格式来表达C++的多态性;以及
  • 更多关于JSON的内容。

结论

序列化将一个对象转换为字节流,存储在磁盘中或通过网络发送到另一台计算机上。反序列化是对序列化流的反转过程,它被称为存档。

基本对象和实例化的对象都可以被序列化。单个基本对象几乎不被序列化。然而,由于一个实例化的对象有基本对象,基本对象与整体一起被序列化。

序列化有一个缺点,它暴露了C++对象的私有成员。这个问题可以通过在二进制中进行序列化来解决。通过文本,可以发送元数据来指示私有成员;但另一端的程序员可能仍然知道这些私有成员。

你可能已经将二进制程序保存到磁盘中,或通过电子邮件发送二进制或源代码程序,你可能会想:为什么只保存或发送对象。那么,在C++中,你可能已经意识到,整个库可能只由一个类组成,可能还有一些继承性。这个类可能比许多短的C++程序还要长。所以,发送对象的一个原因是有些对象太大。面向对象的编程(OOP)涉及到对象的互动,类似于动物、植物和工具的互动。另一个原因是,OOP正在改进,程序员更喜欢处理对象,而不是整个应用程序,后者可能太大。

C++还没有一个标准的文本或二进制的存档格式,尽管有用于C++序列化和反序列化的序列化库。它们中没有一个是真正令人满意的。JavaScript的文本归档格式是JSON。JSON可以与任何计算机语言一起使用。所以,有了上面的指南,你应该可以制作出自己的C++串联和解串联的库。