boost::serialization 多态(polymorphic)序列化技巧及分析

    假如某段程序中我们只记录了一些虚基类指针对象,想把这些对象的完整信息(包括子类信息)序列化时,就需要用到boost的多态序列化技术。

    很简单,只要修改两处地方就可以了:

    (1)保证基类有一个虚函数(无所谓private、public);

    (2)使用boost的宏BOOST_CLASS_EXPORT_GUID将子类export一下;


    第二点需要特别注意下,有一个技巧,我们可能会习惯与在头文件定义子类的同时把BOOST_CLASS_VERSION和BOOST_CLASS_EXPORT_GUID这些宏也声明在头文件里,这是不可取的,会产生如下编译错误:

boost::serialization 多态(polymorphic)序列化技巧及分析_第1张图片

    其实BOOST_CLASS_EXPORT_GUID这个宏也是定义了一堆泛型结构体,其中一个结构体(init_guid)有一个静态成员变量,就是说他重复定义了。解决方法是将这个宏放到一个cpp文件里(比如与子类头文件child.h相对应的child.cpp文件,这个思路也是在苟延残喘的google里搜到的,再次对封杀google表示强烈的谴责!)。

    还需要注意一点,这个cpp文件必须要包含“xml_oarchive.hpp”、“xml_iarchive.hpp”两个头文件(文本、二进制序列方式应该也包含相应的两个头文件),因为在这两个头文件里使用了一个叫做“BOOST_SERIALIZATION_REGISTER_ARCHIVE”的宏,这个也是BOOST_CLASS_EXPORT_GUID能发挥作用所必须的,否则运行时会抛出异常“derived class not registered or exported”,也就是说子类没有export。


    完整示例:

    Point.h

#ifndef _POINT_H_
#define _POINT_H_

#include 
#include 
#include 
#include 

using namespace boost;

class Point
{
private:
	// 基类有一个虚函数,boost序列化时就会按多态处理
	virtual void _Empty() {}

public:
	double X;
	double Y;

	template< typename Archive >
	void serialize( Archive &ar, const unsigned int /* version */ )
	{
		ar & BOOST_SERIALIZATION_NVP( X );
		ar & BOOST_SERIALIZATION_NVP( Y );
	}
};

class Point3 : public Point
{
public: 
	double Z;

	Point3()// 子类必须有一个默认构造函数,因为反序列化过程中会自动创建子类对象(T *t = new T())
	{
		X = Y = Z = 0.0;
	}

	Point3( double x, double y, double z )
	{
		X = x;
		Y = y;
		Z = z;
	}

	template< typename Archive >
	void serialize( Archive &ar, const unsigned int /* version */ )
	{
		ar & serialization::make_nvp( "Base", 
			serialization::base_object< Point >( *this ) );
		ar & BOOST_SERIALIZATION_NVP( Z );
	}
};

#endif

    Point.cpp(可以没有任何方法实现,只放一个export的宏)

#include "Point.h"

BOOST_CLASS_EXPORT_GUID( Point3, "Point3" );


    ConsoleApplication1.cpp

#include 
#include 
#include 
#include 
#include 

#include "Point.h"

using namespace std;
using namespace boost;

int main(int argc, char* argv[])
{
	Point *_Pnt2 = new Point3( 1, 2, 3 );

	// 注意必须序列化指针对象,否则无法视为多态处理
	// xml_oarchive会判断(boost\archive\detail\oserializer.hpp polymorphic::save方法中)
	// 序列化对象的真实类型(true_type = Point3),其实是将Point3的信息记录下来了,
	// 这些关于类和继承的信息同时也记录在了xml文件中为反序列化提供依据

	ofstream ofile( "proj.dat" );
	archive::xml_oarchive oa( ofile );
	oa << serialization::make_nvp( "Point", _Pnt2 );
	ofile.close();


	// 反序列化时仍然使用基类指针(还可以是Point3对象或Point3指针,但不可以是Point对象),
	// xml_iarchive会根据序列化文件内容判断(basic_iarchive::load_pointer方法中,
	// 在boost_1_55_0\libs\serialization\src\basic_iarchive.cpp中实现),
	// 实际上为_Pnt2e分配(new)一个Point3的内存,所以这里不需要手动new,那样反而会造成内存泄露
	ifstream ifile( "proj.dat" );
	archive::xml_iarchive ia( ifile );
	Point *_Pnt2e;
	ia >> serialization::make_nvp( "Point", _Pnt2e );
	ifile.close();

	Point3 *_Pnt3e = ( Point3* )_Pnt2e;
	cout << "Point3 : X = " << _Pnt3e->X << 
		" Y = " << _Pnt3e->Y << " Z = " << _Pnt3e->Z << endl;

	return 0;
}

序列化xml文件,会智能的记录子类的完整信息:

boost::serialization 多态(polymorphic)序列化技巧及分析_第2张图片


运行结果:

boost::serialization 多态(polymorphic)序列化技巧及分析_第3张图片


你可能感兴趣的:(boost)