C++基本功之 对象序列化

稍微正式一点的应用都会用到对象的序列化/反序列化操作,常见的需求包括:

对象的持久存储。比如把一个对象存储到文件;在需要的时候,再把对象从文件中读出来;

对象的传递。比如要把一个对象通过管道,socket等任何手段传送到对端;

从数据构建对象。对象类型未知,但是我们可以从数据中构建一个对象出来。

 

我们现在来分析这些需求。看看C++如何有效地序列化/反序列化对象。下文中,凡提到序列化,都包含相应的反序列化。

 

一个对象的状态由其所有的内部成员状态决定。所以序列化对象其实可以等价于序列化其内部对象,递归地,其内部对象的序列化又可以归于构成这些内部对象的序列化。我们可以发现,到了最后,所有的对象构成都归于基本类型的序列化。

 

注意,这里的讨论并不适用于任何的资源管理类对象。

 

首先,我们需要的是最基本的支持,亦即对C++基本类型的序列化和反序列化;同时,由于标准库中的字符串类使用极为广泛,我们同样加入支持;最后,我们也加入对非格式的POD数据的支持,这样,据大多数的序列化需求应该可以得到满足。以下直接给出实现,其后是简单的说明,请仔细揣摩。

 

说明:

1. 使用独立的名字空间,避免名字冲突;

2. 对于bool型,理论上使用一个bit就可以表达其所有的信息。但是我们实际使用还是一个字节,因为这是内存操作的最小单位。为了有效地利用额外的信息,我们这里加入了对bool的校验,使用两个特殊的值;这两个值可以是任意值,只要不同即可。

3. 实现两个类,分别完成基本对象,字符串及其宽字符版本以及POD数据的序列化和反序列化;

4. 使用成员模板来消除基本对象序列化/反序列话过程中的代码重复;

5. 对于I/O操作失败,我们直接抛出异常。注意,这不是临时方案。而是经过仔细设计的序列化/反序列化过程的错误处理机制;

6. 构造这些对象需要输出或输入流对象,而不仅仅限于文件;

 

有了这个基础,我们就可以设计通用的序列化/反序列化接口了,非常简单:

 

 

那么,这个接口怎么使用呢?假设你有如下类,如果实现对其序列化/反序列化的支持呢?

 

 

下面就是实现代码以及用来测试的代码:

 

 

注意到了吗?实现一个对象的序列化/反序列化操作需要:

1. 从接口serializable中继承

2. 实现相应的接口。对于序列化,按照顺序依次把成员写入流;对于反序列化,则要严格按照相反的顺序依次读入

3. 如果某个成员不是基本数据类型,有两种选择:a. 实现该成员所属类型的序列化/反序列化,然后直接调用之;b. 直接序列化该成员的子成员。这样做会严重破坏对象的完整性,所以非常不推荐使用。

 

实现了对象的序列话之后,使用起来就特别容易了。在我们的测试代码中,我们把对象序列化为一个字串,然后反序列化之到另一个对象。我们最后得到两个状态完全一致的对象。如果我们把该字串通过socket传到远方,实际上就是对象的远程传递了。所有流行的远程对象调用都是用类似的基础机制达成其目的。

 

 

 

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值