zoukankan      html  css  js  c++  java
  • boost::serialization 用基类指针转存派生类(错误多多,一波三折)

    boost::serialization 也支持c++的多态,这样我们就能够通过使用基类的指针来转存派生类,
    我们接着上一篇( 

    boost::serialization(2)序列化基类

    )的样例来看:

    基类和派生类的代码例如以下:

    class student_info
    {
    public:
    	student_info() {}
    	virtual ~student_info() {}
    	student_info(const std::string& sn, const std::string& snm, const std::string& sg)
    		: name_(sn), number_(snm), grade_(sg)
    	{
    	}
    
    	virtual void print_info() const
    	{
    		std::cout << name_ << " " << number_ << " " << grade_ << std::endl;
    	}
    
    private:
    	friend class boost::serialization::access;
    	template<typename Archive>
    	void serialize(Archive& ar, const unsigned int version)
    	{
    		ar & BOOST_SERIALIZATION_NVP(name_);
    		ar & BOOST_SERIALIZATION_NVP(number_);
    		ar & BOOST_SERIALIZATION_NVP(grade_);
    	}
    
    private:
    	std::string name_;
    	std::string number_;
    	std::string grade_;
    };
    
    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)
    		: student_info(sn, snm, sg), age_(age)
    	{
    
    	}
    
    	virtual void print_info()
    	{
    		student_info::print_info();
    		std::cout << age_ << std::endl;
    	}
    
    private:
    	friend class boost::serialization::access;
    	template<typename Archive>
    	void serialize(Archive& ar, const unsigned int version)
    	{
    		ar & boost::serialization::base_object<student_info>(*this);
    		ar & BOOST_SERIALIZATION_NVP(age_);
    	}
    
    private:
    	int age_;
    };
    在派生类中使用了基类的基类的序列化: ar & boost::serialization::base_object<student_info>(*this);
    以下我们来看怎么使用基类的指针转存派生类:
    save的代码:
    void save()
    {
    	std::ofstream ofs("t7.xml");
    	boost::archive::xml_oarchive oa(ofs);
    	student_info* sdinfo = new middle_student("wyp", "0099", "1", 15);//#1
    	oa << BOOST_SERIALIZATION_NVP(sdinfo);//#2
    	std::cout << "xxxx" << std::endl;
    	delete sdinfo;
    }
    #1:用一个基类的指针指向了一个用new申请的派生类的指针,非常easy,都知道这就是c++的多态。
    #2:这个代码和曾经的一样,还是用一个宏来包装指针。


    load的代码:

    void load()
    {
    	std::ifstream ifs("t7.xml");
    	boost::archive::xml_iarchive ia(ifs);
    	student_info* sdinfo = NULL;//#1
    	ia >> BOOST_SERIALIZATION_NVP(sdinfo);//#2
    	middle_student* mds = dynamic_cast<middle_student*>(sdinfo);//#3
    	mds->print_info();
    }
    #1:基类的指针
    #2:load的时候也须要宏来包装
    #3:这个大家都熟悉


    測试代码:

    void fun()
    {
    	save();
    	load();
    }
    编译执行!。

    。。。

    。。
    结果抛出异常:boost::archive::archive_exception at memory location 0x0017eb30...
    google了一下,以下链接给出了一个解决方法
    http://stackoverflow.com/questions/1332602/how-to-serialize-derived-template-classes-with-boost-serialize
    大概分为3个步骤:
    步骤1:BOOST_SERIALIZATION_ASSUME_ABSTRACT(className),用这个宏来告诉boost className是一个抽象类
    步骤2:在save操作中注冊派生类:oa.template register_type<middle_student>(NULL),
           一定要在oa << BOOST_SERIALIZATION_NVP(sdinfo)之前注冊。
    步骤3:在load操作中注冊派生了:ia.template register_type<middle_student>(NULL)
           一定要在ia >> BOOST_SERIALIZATION_NVP(sdinfo)之前注冊。


    改动后的代码例如以下:

    void save()
    {
    	std::ofstream ofs("t7.xml");
    	boost::archive::xml_oarchive oa(ofs);
    	oa.template register_type<middle_student>(NULL);
    	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);
    	ia.template register_type<middle_student>(NULL);
    	student_info* sdinfo = NULL;
    	ia >> BOOST_SERIALIZATION_NVP(sdinfo);
    	middle_student* mds = dynamic_cast<middle_student*>(sdinfo);
    	mds->print_info();
    }
    好这下应改没有异常了吧。

    结果编译就出错了!


    错误在这个函数里面

     // Anything not an attribute and not a name-value pair is an
        // error and should be trapped here.
        template<class T>
        void save_override(T & t, BOOST_PFTO int)
        {
            // If your program fails to compile here, its most likely due to
            // not specifying an nvp wrapper around the variable to
            // be serialized.
            BOOST_MPL_ASSERT((serialization::is_wrapper< T >));
            this->detail_common_oarchive::save_override(t, 0);
        }
    看凝视就知道了,序列化时存在有些数据没有包装,就是没实用那个宏。

    就细致看一下序列化的代码发现这段代码中有一个没用宏来包装:

    private:
    	friend class boost::serialization::access;
    	template<typename Archive>
    	void serialize(Archive& ar, const unsigned int version)
    	{
    		ar & boost::serialization::base_object<student_info>(*this);//here!!!!!!!!!!!
    		ar & BOOST_SERIALIZATION_NVP(age_);
    	}
    在调用基类的序列化时没用宏包装

    改动例如以下:

    private:
    	friend class boost::serialization::access;
    	template<typename Archive>
    	void serialize(Archive& ar, const unsigned int version)
    	{
    		//ar & boost::serialization::base_object<student_info>(*this);
    		ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(student_info);
    		ar & BOOST_SERIALIZATION_NVP(age_);
    	}
    编译执行ok!

    执行结果例如以下 t7.xml

    <?xml version="1.0" encoding="UTF-8" standalone="yes" ?

    >
    <!DOCTYPE boost_serialization>
    <boost_serialization signature="serialization::archive" version="10">
    <sdinfo class_id="0" tracking_level="1" version="0" object_id="_0">
    <student_info class_id="1" tracking_level="1" version="0" object_id="_1">
    <name_>wyp</name_>
    <number_>0099</number_>
    <grade_>1</grade_>
    </student_info>
    <age_>15</age_>
    </sdinfo>
    </boost_serialization>

    完整代码例如以下

    #include <fstream>
    #include <iostream>
    #include <algorithm>
    #include <boost/archive/xml_iarchive.hpp>
    #include <boost/archive/xml_oarchive.hpp>
    #include <boost/serialization/base_object.hpp>
    
    class student_info
    {
    public:
    	student_info() {}
    	virtual ~student_info() {}
    	student_info(const std::string& sn, const std::string& snm, const std::string& sg)
    		: name_(sn), number_(snm), grade_(sg)
    	{
    	}
    
    	virtual void print_info() const
    	{
    		std::cout << name_ << " " << number_ << " " << grade_ << std::endl;
    	}
    
    private:
    	friend class boost::serialization::access;
    	template<typename Archive>
    	void serialize(Archive& ar, const unsigned int version)
    	{
    		ar & BOOST_SERIALIZATION_NVP(name_);
    		ar & BOOST_SERIALIZATION_NVP(number_);
    		ar & BOOST_SERIALIZATION_NVP(grade_);
    	}
    
    private:
    	std::string name_;
    	std::string number_;
    	std::string grade_;
    };
    
    BOOST_SERIALIZATION_ASSUME_ABSTRACT(student_info)
    
    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)
    		: student_info(sn, snm, sg), age_(age)
    	{
    
    	}
    
    	virtual void print_info()
    	{
    		student_info::print_info();
    		std::cout << age_ << std::endl;
    	}
    
    private:
    	friend class boost::serialization::access;
    	template<typename Archive>
    	void serialize(Archive& ar, const unsigned int version)
    	{
    		ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(student_info);
    		ar & BOOST_SERIALIZATION_NVP(age_);
    	}
    
    private:
    	int age_;
    };
    
    void save()
    {
    	std::ofstream ofs("t7.xml");
    	boost::archive::xml_oarchive oa(ofs);
    	oa.template register_type<middle_student>(NULL);
    	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);
    	ia.template register_type<middle_student>(NULL);
    	student_info* sdinfo = NULL;
    	ia >> BOOST_SERIALIZATION_NVP(sdinfo);
    	middle_student* mds = dynamic_cast<middle_student*>(sdinfo);
    	mds->print_info();
    }
    
    void fun()
    {
    	save();
    	load();
    }







  • 相关阅读:
    企业库应用实践系列五:创建模板引擎Library
    关于HtmlHelper:是MVC自作聪明,还是我不够明白?
    企业库应用实践系列二:对象创建原理详解
    企业库应用实践系列三:自定义构造函数
    专业导论 计算机科学概论
    企业短期项目,缺人手
    光脚丫学LINQ(040):引发未将对象引用设置到对象的实例的异常
    光脚丫学LINQ(045):如何表示计算所得列(LINQ to SQL)
    光脚丫学LINQ(042):如何将列表示为由数据库生成的列
    光脚丫学LINQ(043):为实体类的列成员指定在数据库中的数据类型
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6852139.html
Copyright © 2011-2022 走看看