输出档案(archive)cM于输出数据流(stream)。数据能通过<< ?& 操作W存储到档案(archive)?
ar << data;
ar & data;
输入档案(archive)cM于输入数据流(stream)。数据能通过>> ?& 操作W从档案(archive)中装载?
ar >> data;
ar & data;
对于原始数据cdQ当q些操作调用的时候,数据是简单的“被存储/被装载?“到/从?档案(archive)。对于类(class)数据cdQ类的serialize 函数被调用。对上面的操作,每个serialize 函数用来“存?装蝲”其数据成员。这个处理采用递归的方式,直到所有包含在cM的数据“被存储/被装载”?
通常用serialize 函数来存储和装蝲cȝ数据成员?
q个库包含一个叫 demo.cpp 的程序,用于介绍如何用这个库。下面,我们从这个demo摘录代码Q来介绍q个库应用的最单情形?pre>
#include <fstream>
// include headers that implement a archive in simple text format
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
/////////////////////////////////////////////////////////////
// gps coordinate
//
// illustrates serialization for a simple type
//
class gps_position
{
private:
friend class boost::serialization::access;
// When the class Archive corresponds to an output archive, the
// & operator is defined similar to <<. Likewise, when the class Archive
// is a type of input archive the & operator is defined similar to >>.
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & degrees;
ar & minutes;
ar & seconds;
}
int degrees;
int minutes;
float seconds;
public:
gps_position(){};
gps_position(int d, int m, float s) :
degrees(d), minutes(m), seconds(s)
{}
};
int main() {
// create and open a character archive for output
std::ofstream ofs("filename");
boost::archive::text_oarchive oa(ofs);
// create class instance
const gps_position g(35, 59, 24.567f);
// write class instance to archive
oa << g;
// close archive
ofs.close();
// ... some time later restore the class instance to its orginal state
// create and open an archive for input
std::ifstream ifs("filename", std::ios::binary);
boost::archive::text_iarchive ia(ifs);
// read class state from archive
gps_position newg;
ia >> newg;
// close archive
ifs.close();
return 0;
}
对于每个通过序列化“被存储”的c,必须存在一个函数去实现“存储”其所有状态数据。对于每个通过序列化“被装蝲”的c,必须存在一个函数来实现“装载”其所有状态数据。在上面的例子中Q这些函数是模板成员函数serialize?
在上例是侵入的设计。类是需要由其实例来序列化,来改变。这在某些情形是困难的。一个等L可选的设计如下Q?pre>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
class gps_position
{
public:
int degrees;
int minutes;
float seconds;
gps_position(){};
gps_position(int d, int m, float s) :
degrees(d), minutes(m), seconds(s)
{}
};
namespace boost {
namespace serialization {
template<class Archive>
void serialize(Archive & ar, gps_position & g, const unsigned int version)
{
ar & g.degrees;
ar & g.minutes;
ar & g.seconds;
}
} // namespace serialization
} // namespace boost
q种情况生成的serialize 函数不是gps_positioncȝ成员函数。这有异曲同工之妙?
非R入序列化主要应用在不改变cd义就可实现类的序列化。ؓ实现q种可能Q类必须提供_的信息来更新cȝ态。在q个例子中,我们假设cLpublic成员。仅当提供够信息来存储和装载的c,才能不改变类自nQ在外部来序列化cȝ态?
一个可序列化的c,可拥有可序列化的成员Q例如:
class bus_stop
{
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & latitude;
ar & longitude;
}
gps_position latitude;
gps_position longitude;
protected:
bus_stop(const gps_position & lat_, const gps_position & long_) :
latitude(lat_), longitude(long_)
{}
public:
bus_stop(){}
// See item # 14 in Effective C++ by Scott Meyers.
// re non-virtual destructors in base classes.
virtual ~bus_stop(){}
};
q里Q类cd的成员被序列化,恰如原始cd被序列化一栗?
注意Q类bus_stop的实例“存储”时Q其归档(archive)操作W将调用latitude ?longitude的serialize 函数。这依ơ调用定义在gps_position中的serialize 来被“存储”。这U手法中Q通过bus_stop
的归?archive)操作W?整个数据l构被存?bus_stop
是它的根条目?
zcd包含其基cȝ序列化?
#include <boost/serialization/base_object.hpp>
class bus_stop_corner : public bus_stop
{
friend class boost::serialization::access;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// serialize base class information
ar & boost::serialization::base_object<bus_stop>(*this);
ar & street1;
ar & street2;
}
std::string street1;
std::string street2;
virtual std::string description() const
{
return street1 + " and " + street2;
}
public:
bus_stop_corner(){}
bus_stop_corner(const gps_position & lat_, const gps_position & long_,
const std::string & s1_, const std::string & s2_
) :
bus_stop(lat_, long_), street1(s1_), street2(s2_)
{}
};
注意在派生类中不要直接调用其基类的序列化函数。这样做看似工作Q实际上l过跟踪实例用于存储来消除冗余的代码。它也绕q写到档案中cȝ版本信息的代码。因此,L声明serialize 作ؓU有函数。声明friend boost::serialization::access 运行序列化库存取私有变量和函数?
假设我们定义了bus route包含一lbus stops。假定:
- 我们可以有几Ubus stop的类型(Cbus_stop是一个基c)?
- 一个所l的 bus_stop可以展现多于一个的路线?
一个bus route 用一l指向bus_stop的指针来描述是方便的?pre>
class bus_route
{
friend class boost::serialization::access;
bus_stop * stops[10];
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
int i;
for(i = 0; i < 10; ++i)
ar & stops[i];
}
public:
bus_route(){}
};
数组stops 的每个成员将被序列化。但是,C每个成员是个指针?- 实际含义是什么?序列化整个对象是要求在另一个地方和旉重新构造原始数据结构。用指针Z完成q些Q存储指针的值是不够的,指针指向的对象必d储。当成员最后被装蝲Q一个新的对象被创徏Q新的指针被装蝲到类的成员中?
所有这一切是由序列化库自动完成的。通过指针兌的对象,上述代码能完成存储和装蝲?
事实上上q方案比较复杂。序列化库能出被序列化的对象是一个数l,生上q等L代码。因此上qC码能更短的写为:
class bus_route
{
friend class boost::serialization::access;
bus_stop * stops[10];
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & stops;
}
public:
bus_route(){}
};
上面的例子用数组成员。更多的如此的一个应用用STL容器为如此的目的。序列化库包含ؓ所有STL容器序列化的代码。因此,下种Ҏ正如我们所预期的样子工作?pre>
#include <boost/serialization/list.hpp>
class bus_route
{
friend class boost::serialization::access;
std::list<bus_stop *> stops;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & stops;
}
public:
bus_route(){}
};
假设我们对bus_routecL意,在品中使用它。一D|间后Q发觉bus_route c需要包含线路驾驶员的名字。因此新版本如下Q?
#include <boost/serialization/list.hpp>
#include <boost/serialization/string.hpp>
class bus_route
{
friend class boost::serialization::access;
std::list<bus_stop *> stops;
std::string driver_name;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
ar & driver_name;
ar & stops;
}
public:
bus_route(){}
};
好,完毕Q异?..会发生在d旧版本所生成的数据文件时。如何考虑版本问题Q?
通常Q序列化库ؓ每个被序列化的类在档案中存储版本受缺省值是0。当档案装蝲Ӟ存储的版本号可被d。上qC码可修改如下Q?pre>
#include <boost/serialization/list.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/version.hpp>
class bus_route
{
friend class boost::serialization::access;
std::list<bus_stop *> stops;
std::string driver_name;
template<class Archive>
void serialize(Archive & ar, const unsigned int version)
{
// only save/load driver_name for newer archives
if(version > 0)
ar & driver_name;
ar & stops;
}
public:
bus_route(){}
};
BOOST_CLASS_VERSION(bus_route, 1)
Ҏ个类通过应用的版本,没有必要l护一个版本文件。一个文件版本是所有它l成的类的版本的联合。系l允许程序和以前版本的程序创建的档案向下兼容?
serialize函数是简单,z,q且保证cL员按同样的顺序(序列化系l的keyQ被存储/被装载。可是有像这里例子一P装蝲和存储不一致的情Ş。例如,一个类有多个版本的情况发生。上q情形能重写为:
#include <boost/serialization/list.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/version.hpp>
#include <boost/serialization/split_member.hpp>
class bus_route
{
friend class boost::serialization::access;
std::list<bus_stop *> stops;
std::string driver_name;
template<class Archive>
void save(Archive & ar, const unsigned int version) const
{
// note, version is always the latest when saving
ar & driver_name;
ar & stops;
}
template<class Archive>
void load(Archive & ar, const unsigned int version)
{
if(version > 0)
ar & driver_name;
ar & stops;
}
BOOST_SERIALIZATION_SPLIT_MEMBER()
public:
bus_route(){}
};
BOOST_CLASS_VERSION(bus_route, 1)
BOOST_SERIALIZATION_SPLIT_MEMBER() 宏生成调?save ?load的代码,依赖于是否档案被用于“存储”或“装载”?
我们q里讨论聚焦到cȝ序列化能力上。被序列化的数据的实际编码实C档案(archive)cM。被序列化的数据是所选档?archive)cȝ序列化的产物??key设计军_q两个组件的独立性。允怓Q何序列化的规范可用于M档案(archive)?
在这指南中Q我们用了一个档案类-用于存储的text_oarchive和用于装载的text_iarchivecR在库中其他档案cȝ接口完全一致。一旦类的序列化已经被定义,c能被序列化CQ何档案类型?
假如当前的档案集不能提供某个属性,格式Q或行ؓ需要特化的应用。要么创Z个新的要么从已有的里面衍生一个。将在后l文档中描述?
注意我们的例子save和loadE序数据在一个程序中Q这是ؓ了讨论方便而已。通常Q被装蝲的档案或许在或许不在同一个程序中?
T完整的演C程?- demo.cpp 包括Q?
- 创徏各种cd?stops, routes ?schedules
- 昄?
- 序列化到一个名?"testfile.txt"的文件中
- q原到另一个结构中
- 昄被存储的l构
q个E序的输?/a> 分证实了对序列化pȝ所有的要求Q都在这个系l中体现了。对序列化文件是ASCII文本?a >档案文g的内?/a> 能被昄?/p>
]]>