天天看點

boost::serialization 用基類指針轉存派生類(錯誤多多,一波三折) boost::serialization(2)序列化基類

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申請的派生類的指針,很簡單,都知道這就是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();
}
           

好這下應改沒有異常了吧。

結果編譯就出錯了!!!

boost::serialization 用基類指針轉存派生類(錯誤多多,一波三折) boost::serialization(2)序列化基類

錯誤在這個函數裡面

// 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();
}
           

繼續閱讀