首页 > 代码库 > BOOST_CLASS_EXPORT

BOOST_CLASS_EXPORT

用基类的指针去转存派生类时除了上一篇boost::serialization 用基类指针转存派生类(错误多多,一波三折)之外,还有另一种更简单的方法:
用BOOST_CLASS_EXPORT宏。下面我们来分析怎样用BOOST_CLASS_EXPORT来实现
用基类的指针去转存派生类。

首先来看前面实例的一段代码:

void save()
{
	std::ofstream ofs("t7.xml");
	boost::archive::xml_oarchive oa(ofs);
	student_info* sdinfo = new middle_student("wyp", "0099", "1", 15);
	oa << BOOST_SERIALIZATION_NVP(sdinfo);//#1
	delete sdinfo;
}
当程序执行到#1时就会抛出异常:boost::archive::archive_exception at memory location 0x0017eb30...

boost文档解释是派生类没有实例化(这里是个人理解。。。。“实例化”到底什么意思也不太理解。。。)。

当我们在#1前面加上注册的代码时

oa.template register_type<middle_student>(NULL);
实际上就相当于“实例化”,看看register_type的实现代码:

 template<class T>
    const basic_pointer_oserializer * 
    register_type(const T * = NULL){
        const basic_pointer_oserializer & bpos =
            boost::serialization::singleton<
                pointer_oserializer<Archive, T>
            >::get_const_instance();
        this->This()->register_basic_serializer(bpos.get_basic_serializer());
        return & bpos;
    }
代码大概就是用单件模式申请一个对象的const指针,估计这个实例化就是为T申请内存。

然后看看BOOST_CLASS_EXPORT宏

#define BOOST_CLASS_EXPORT(T)                       BOOST_CLASS_EXPORT_GUID(                            T,                                              BOOST_PP_STRINGIZE(T)                       )                                           \
实际上是BOOST_CLASS_EXPORT_GUID宏的定义,继续看看这个宏

#define BOOST_CLASS_EXPORT_GUID(T, K)                                  BOOST_CLASS_EXPORT_KEY2(T, K)                                          BOOST_CLASS_EXPORT_IMPLEMENT(T)                                        \
原来这个宏展开式两个宏的定义,先看BOOST_CLASS_EXPORT_KEY2(T,K)这个宏

#define BOOST_CLASS_EXPORT_KEY2(T, K)          namespace boost {                              namespace serialization {                      template<>                                     struct guid_defined< T > : boost::mpl::true_ {}; template<>                                     inline const char * guid< T >(){                     return K;                                  }                                              } /* serialization */                          } /* boost */                                  \
这个宏实际上做了一件这样的事:返回了一个唯一标记T的const char*字符串。

接下看看看BOOST_CLASS_EXPORT_IMPLEMENT(T)这个宏:

#define BOOST_CLASS_EXPORT_IMPLEMENT(T)                          namespace boost {                                            namespace archive {                                          namespace detail {                                           namespace extra_detail {                                     template<>                                                   struct init_guid< T > {                                          static guid_initializer< T > const & g;                  };                                                           guid_initializer< T > const & init_guid< T >::g =                ::boost::serialization::singleton<                               guid_initializer< T >                                    >::get_mutable_instance().export_guid();                 }}}}                                                     \
看看这段代码是不是和register_type实现的代码很类似:用单件模式返回一个指针。这就验证了“实例化”其实就是申请T的内存。

至此我们可以看出BOOST_CLASS_EXPORT和register_type具有类似的功能:(boost 文档)

  • Instantiates code which is not otherwise referred to.
  • Associates an external identifier with the class to be serialized. The fact that the class isn‘t explicitly referred to implies this requirement.
  • 实例化未被引用的代码。
  • 用一个外部的标识符关联被序列化的类。事实上该类未被显式引用即暗示这一要求。
好,转回来,现在看看具体怎样用BOOST_CLASS_EXPORT这个宏来实现

1.基类文件:student_info.h

class student_info
	{
	public:
		student_info() {}
		virtual ~student_info() {}
		student_info(const std::string& sn, const std::string& snm, const std::string& sg);
		virtual void print_info() const;
	private:
		friend class boost::serialization::access;
		template<typename Archive>
		void serialize(Archive& ar, const unsigned int version);
	private:
		std::string name_;
		std::string number_;
		std::string grade_;
	};
2派生类文件middle_student.h

class middle_student : public student_info
	{
	public:
		middle_student() {}
		virtual ~middle_student() {}
		middle_student(const std::string& sn, const std::string& snm, const std::string& sg, int age);
		virtual void print_info();
	private:
		friend class boost::serialization::access;
		template<typename Archive>
		void serialize(Archive& ar, const unsigned int version);
	private:
		int age_;
	};
3.main.cpp

#include <fstream>
#include <boost\archive\text_iarchive.hpp>
#include <boost\archive\text_oarchive.hpp>
#include <boost\serialization\export.hpp>

#include "student_info.h"

#include "middle_student.h"
BOOST_CLASS_EXPORT(middle_student)
//#1
//#2


void save()
{
	std::ofstream ofs("t7.xml");
	boost::archive::xml_oarchive oa(ofs);
	student_info* sdinfo = new middle_student("wyp", "0099", "1", 15);
	oa << BOOST_SERIALIZATION_NVP(sdinfo);
	delete sdinfo;
}
void load()
{
	std::ifstream ifs("t7.xml");
	boost::archive::xml_iarchive ia(ifs);
	student_info* sdinfo = NULL;
	ia >> BOOST_SERIALIZATION_NVP(sdinfo);
	middle_student* mds = dynamic_cast<middle_student*>(sdinfo);
	mds->print_info();
}

int main()
{
	save();
	load();
	return 0;
}
看见红色字体的两行没有,就是这样用BOOST_CLASS_EXPORT宏,这样就不用注册派生类。

假如又有一个student_info的派生类xxx_student,且头文件为"xxx_student.h",你只需要

在#1添加#include "xxx_student.h"

在#2添加BOOST_CLASS_EXPORT(xxx_student)

这样你就也能使用基类student_info的指针来转存派生了xxx_student。