当前位置:文档之家› boost-serialization+variant

boost-serialization+variant

boost-serialization+variant
boost-serialization+variant

目录

Boost.serialization 序列化 (1)

1. 概述 (1)

2. 归档 (1)

3. 指针和引用 (11)

4. 对象类层次结构的序列化 (16)

5. 优化用封装函数 (20)

Boost.Variant 变体 (22)

1类摘要 (23)

2访问元素 (24)

3用法 (24)

4访问器 (25)

5与any的区别 (27)

Boost.serialization 序列化

1. 概述

Boost C++ 的序列化库允许将 C++ 应用程序中的对象转换为一个字节序列,此序列可以被保存,并可在将来恢复对象的时候再次加载。各种不同的数据格式,包括 XML,只要具有一定规则的数据格式,在序列化后都产生一个字节序列。所有 Boost.Serialization 支持的格式,在某些方面来说都是专有的。比如 XML 格式不同用来和不是用 C++ Boost.Serialization库开发的应用程序交换数据。所有以 XML 格式存储的数据适合于从之前存储的数据上恢复同一个 C++ 对象。XML 格式的唯一优点是序列化的 C++ 对象容易理解,这是很有用的,比如说在调试的时候。

2. 归档

Boost.Serialization 的主要概念是归档。归档的文件是相当于序列化的 C++ 对象的一个字节流。对象可以通过序列化添加到归档文件,相应地也可从归档文件中加载。为了恢复和之前存储相同的 C++ 对象,需假定数据类型是相同的。

下面看一个简单的例子。

#include

#include

int main()

{

boost::archive::text_oarchiveoa(std::cout);

inti = 1;

oa<

}

Boost.Serialization 提供了多个归档类,如boost::archive::text_oarchive 类,它定义在boost/archive/text_oarchive.hpp文件中。

boost::archive::text_oarchive,可将对象序列化为文本流。上面的应用程序将1写出到标准输出流。

可见,boost::archive::text_oarchive 类型的对象oa可以用来像流 (stream) 一样通过<<来序列化对象。尽管如此,归档也不能被认为是可以存储任何数据的常规的流。为了以后恢复数据,必须以相同的顺序使用和先前存储时用的一样的数据类型。下面的例子序列化和恢复了int类型的变量。

#include

#include

#include

#include

void save()

{

std::ofstream file("archiv.txt");

boost::archive::text_oarchiveoa(file);

inti = 1;

oa<

}

void load()

{

std::ifstream file("archiv.txt");

boost::archive::text_iarchiveia(file);

inti = 0;

ia>>i;

std::cout<

}

int main()

{

save();

load();

}

当boost::archive::text_oarchive被用来把数据序列化为文本流,

boost::archive::text_iarchive就用来从文本流恢复数据。为了使用这些类,必须包含boost/archive/text_iarchive.hpp头文件。

归档的构造函数需要一个输入或者输出流作为参数。流分别用来序列化或恢复数据。虽然上面的应用程序使用了一个文件流,其他流,如 stringstream 流也是可以的。

#include

#include

#include

#include

std::stringstreamss;

void save()

{

boost::archive::text_oarchiveoa(ss);

inti = 1;

oa<

}

void load()

{

boost::archive::text_iarchiveia(ss);

inti = 0;

ia>>i;

std::cout<

}

int main()

{

save();

load();

}

这个应用程序也向标准输出流写了1。然而,与前面的例子相比, 数据却是用stringstream 流序列化的。

到目前为止,原始的数据类型已经被序列化了。接下来的例子演示如何序列化用户定义类型的对象。

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age)

: age_(age)

{

}

int age() const

{

return age_;

}

private:

friend class boost::serialization::access;

template

void serialize(Archive &ar, const unsigned int version)

{

ar& age_;

}

int age_;

};

void save()

{

boost::archive::text_oarchiveoa(ss);

person p(31);

oa<< p;

}

void load()

{

boost::archive::text_iarchiveia(ss);

person p;

ia>> p;

std::cout<

}

int main()

{

save();

load();

}

为了序列化用户定义类型的对话,serialize()函数必须定义,它在对象序列化或从字节流中恢复是被调用。由于serialize ()函数既用来序列化又用来恢复数据, Boost.Serialization 除了<<和>>之外还提供了&操作符。如果使用这个操作符,就不再需要在serialize()函数中区分是序列化和恢复了。

serialize ()在对象序列化或恢复时自动调用。它应从来不被明确地调用,所以应生命为私有的。这样的话,boost::serialization::access类必须被声明为友元,以允许 Boost.Serialization 能够访问到这个函数。

有些情况下需要添加serialize()函数却不能修改现有的类。比如,对于来自 C++ 标准库或其他库的类就是这样的。

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age)

: age_(age)

{

}

int age() const

{

return age_;

}

private:

friend class boost::serialization::access;

template

friend void serialize(Archive &ar, person &p, const unsigned int version);

int age_;

};

template

void serialize(Archive &ar, person &p, const unsigned int version) {

ar&p.age_;

}

void save()

{

boost::archive::text_oarchiveoa(ss);

person p(31);

oa<< p;

}

void load()

{

boost::archive::text_iarchiveia(ss);

person p;

ia>> p;

std::cout<

}

int main()

{

save();

load();

}

为了序列化那些不能被修改的数据类型,要定义一个单独的函数serialize(),如上面的例子所示。这个函数需要相应的数据类型的引用作为它的第二个参数。

如果要被序列化的数据类型中含有不能经由公有函数访问的私有属性,事情就变得复杂了。在这种情况下,该数据列席就需要修改。在上面应用程序中的serialize ()函数如果不声明为friend ,就不能访问age_属性。

不过还好,Boost.Serialization 为许多C++标准库的类提供了serialize()函数。为了序列化基于 C++ 标准库的类,需要包含额外的头文件。

#include

#include

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age, conststd::string &name)

: age_(age), name_(name)

{

}

int age() const

{

return age_;

}

std::string name() const

{

return name_;

}

private:

friend class boost::serialization::access;

template

friend void serialize(Archive &ar, person &p, const unsigned int version);

int age_;

std::string name_;

};

template

void serialize(Archive &ar, person &p, const unsigned int version) {

ar&p.age_;

ar& https://www.doczj.com/doc/606841000.html,_;

}

void save()

{

boost::archive::text_oarchiveoa(ss);

person p(31, "Boris");

oa<< p;

}

void load()

{

boost::archive::text_iarchiveia(ss);

person p;

ia>> p;

std::cout<

std::cout<

}

int main()

{

save();

load();

}

这个例子扩展了person 类,增加了std::string 类型的名称变量,为了序列化这个属性property, the header file boost/serialization/string.hpp 头文件必须包含,它提供了合适的单独的serialize ()函数。

为了序列化std::string 类型的对象,必须包含

boost/serialization/string.hpp 头文件。这些都定义在和 C++ 标准库头文件名称相对应的头文件中。为了序列化std::vector 类型的对象,必须包含boost/serialization/vector.hpp 头文件。在不同的场合需要包含相应的头文件。

还有一个serialize ()函数的参数version ,该参数起到版本兼容性作用。如果归档需要向前兼容,以支持给定应用程序的未来版本,需要用到版本参数。接下来的例子考虑到person 类的归档需要向前兼容。由于person 的原始版本没有包含任何名称,新版本的person 应该能够处理不带名称的旧的归档。

#include

#include

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age, conststd::string &name)

: age_(age), name_(name)

{

}

int age() const

{

return age_;

}

std::string name() const

{

return name_;

}

private:

friend class boost::serialization::access;

template

friend void serialize(Archive &ar, person &p, const unsigned int version);

int age_;

std::string name_;

};

template

void serialize(Archive &ar, person &p, const unsigned int version) {

ar&p.age_;

if (version > 0)

ar& https://www.doczj.com/doc/606841000.html,_;

}

BOOST_CLASS_VERSION(person, 1)

void save()

{

boost::archive::text_oarchiveoa(ss);

person p(31, "Boris");

oa<< p;

}

void load()

{

boost::archive::text_iarchiveia(ss);

person p;

ia>> p;

std::cout<

std::cout<

}

int main()

{

save();

load();

}

BOOST_CLASS_VERSION 宏用来指定类的版本号。上面例子中person 类的版本号设置为1。如果没有使用BOOST_CLASS_VERSION ,版本号缺省是0。

版本号存储在归档文件中,因此也就是归档的一部份。当一个特定类的版本号通过BOOST_CLASS_VERSION 宏,在序列化时给定时,serialize ()函数的version 参数被设为给定值存储在归档中。如果新版本的person 访问一个包含旧版本序列化对象的归档时,name_ 由于旧版本不含有这个属性而不能恢复。通过这种机制,Boost.Serialization 提供了向前兼容归档的支持。

3. 指针和引用

Boost.Serialization 还能序列化指针和引用。由于指针存储对象的地址,序列化对象的地址没有什么意义,而是在序列化指针和引用时,对象的引用被自动地序列化。

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age)

: age_(age)

{

}

int age() const

{

return age_;

}

private:

friend class boost::serialization::access;

template

void serialize(Archive &ar, const unsigned int version)

{

ar& age_;

}

int age_;

};

void save()

{

boost::archive::text_oarchiveoa(ss);

person *p = new person(31);

oa<< p;

std::cout<

delete p;

}

void load()

{

boost::archive::text_iarchiveia(ss);

person *p;

ia>> p;

std::cout<

std::cout<< p->age() <

delete p;

}

int main()

{

save();

load();

}

上面的应用程序创建了一个新的person 类型的对象,使用new 创建并赋值给指针p 。是指针 - 而不是*p - 被序列化了。Boost.Serialization 自动地通过p 的引用序列化对象本身而不是对象的地址。

如果归档被恢复,p 不必指向相同的地址。而是创建新对象并将它的地址赋值给p 。 Boost.Serialization 只保证对象和之前序列化的对象相同,而不是地址

相同。

由于新式的 C++ 在动态分配内存有关的地方使用智能指针 (smart pointers) ,Boost.Serialization 对此也提供了相应的支持。

#include

#include

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age)

: age_(age)

{

}

int age() const

{

return age_;

}

private:

friend class boost::serialization::access;

template

void serialize(Archive &ar, const unsigned int version) {

ar& age_;

}

int age_;

};

void save()

{

boost::archive::text_oarchiveoa(ss);

boost::scoped_ptrp(new person(31));

oa<< p;

}

void load()

{

boost::archive::text_iarchiveia(ss);

boost::scoped_ptr p;

ia>> p;

std::cout<< p->age() <

}

int main()

{

save();

load();

}

例子中使用了智能指针boost::scoped_ptr 来管理动态分配的person 类型的

对象。为了序列化这样的指针,必须包含boost/serialization/scoped_ptr.hpp 头文件。

在使用boost::shared_ptr 类型的智能指针的时候需要序列化,那么必须包含boost/serialization/shared_ptr.hpp 头文件。

下面的应用程序使用引用替代了指针。

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age)

: age_(age)

{

}

int age() const

{

return age_;

}

private:

friend class boost::serialization::access;

template

void serialize(Archive &ar, const unsigned int version)

{

ar& age_;

}

int age_;

};

void save()

{

boost::archive::text_oarchiveoa(ss);

person p(31);

person&pp = p;

oa<< pp;

}

void load()

{

boost::archive::text_iarchiveia(ss);

person p;

person&pp = p;

ia>> pp;

std::cout<

}

int main()

{

save();

load();

}

可见,Boost.Serialization 还能没有任何问题地序列化引用。就像指针一样,引用对象被自动地序列化。

4. 对象类层次结构的序列化

为了序列化基于类层次结构的对象,子类必须在serialize ()函数中访问boost::serialization::base_object ()。此函数确保继承自基类的属性也能正确地序列化。下面的例子演示了一个名为developer 类,它继承自类person 。

#include

#include

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age)

: age_(age)

{

}

int age() const

{

return age_;

}

private:

friend class boost::serialization::access;

template

void serialize(Archive &ar, const unsigned int version)

{

ar& age_;

}

int age_;

};

class developer

: public person

{

public:

developer()

{

}

developer(int age, conststd::string &language)

: person(age), language_(language)

{

}

std::string language() const

{

return language_;

}

private:

friend class boost::serialization::access;

template

void serialize(Archive &ar, const unsigned int version) {

ar& boost::serialization::base_object(*this); ar& language_;

}

std::string language_;

};

void save()

{

boost::archive::text_oarchiveoa(ss);

developer d(31, "C++");

oa<< d;

}

void load()

{

boost::archive::text_iarchiveia(ss);

developer d;

ia>> d;

std::cout<

std::cout<

}

int main()

{

save();

load();

}

person 和developer 这两个类都包含有一个私有的serialize ()函数,它使得基于其他类的对象能被序列化。由于developer 类继承自person 类,所以它的serialize ()函数必须确保继承自person 属性也能被序列化。

正如在前面章节中提到的,引用对象被自动地序列化。为了让

Boost.Serialization 识别将要序列化的developer 类型的对象,即使指针是person* 类型的对象。developer 类需要相应的声明。这是通过这个

BOOST_CLASS_EXPORT 宏实现的,它定义在boost/serialization/export.hpp 文件中。因为developer 这个数据类型没有指针形式的定义,所以

Boost.Serialization 没有这个宏就不能正确地序列化developer 。

如果子类对象需要通过基类的指针序列化,可以用BOOST_CLASS_EXPORT 宏静态注册完成。BOOST_CLASS_EXPORT 的一个缺点是可能有些注册的类最后是不需要序列化的。 Boost.Serialization 为这种情况提供一种解决方案。调用了register_type ()模板函数。需要注册的类型作为模板参数传入,只有需要序列化的类才注册。

#include

#include

#include

#include

#include

#include

#include

std::stringstreamss;

class person

{

public:

person()

{

}

person(int age)

: age_(age)

{

}

virtualint age() const

{

return age_;

}

private:

friend class boost::serialization::access;

template

void serialize(Archive &ar, const unsigned int version) {

ar& age_;

}

int age_;

};

class developer

: public person

{

public:

developer()

{

}

developer(int age, conststd::string &language)

: person(age), language_(language)

{

}

std::string language() const

{

return language_;

}

private:

friend class boost::serialization::access;

template

void serialize(Archive &ar, const unsigned int version)

{

ar& boost::serialization::base_object(*this);

ar& language_;

}

std::string language_;

};

void save()

{

boost::archive::text_oarchiveoa(ss);

oa.register_type();

person *p = new developer(31, "C++");

oa<< p;

delete p;

}

void load()

{

boost::archive::text_iarchiveia(ss);

ia.register_type();

person *p;

ia>> p;

std::cout<< p->age() <

delete p;

}

int main()

{

save();

load();

}

5. 优化用封装函数

在理解了如何序列化对象之后,本节介绍用来优化序列化过程的封装函数。通过这个函数,对象被打上标记允许 Boost.Serialization 使用一些优化技术。

下面例子使用不带封装函数的 Boost.Serialization 。

相关主题
文本预览
相关文档 最新文档