boost::serialization 用基类指针转存派生类(错误多多,一波三折)

原创 2014年05月03日 14:56:54
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();
}
好这下应改没有异常了吧。

结果编译就出错了!!!


错误在这个函数里面

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







《虚函数——用基类指针访问派生类中的成员函数》

/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2011, 烟台大学计算机学院学生 * All rights reserved. * 文件名称: 《...
  • sdliujiangbo
  • sdliujiangbo
  • 2012年07月03日 10:33
  • 6276

C++基类、派生类指针转换

主要用到static_cast和dynamic_cast 自己对两个的理解就是
  • panhe1992
  • panhe1992
  • 2014年08月05日 10:50
  • 1223

C++中,基类的指针指向派生类的对象

1,基类的指针指向派生类的对象,指向的是派生类中基类的部分。所以只能操作派生类中从基类中继承过来的数据和基类自身的数据。 2,C++的多态性可以解决基类指针不能操作派生类的数据成员的问题。 例子如下:...
  • u010711820
  • u010711820
  • 2017年01月19日 16:12
  • 2175

为什么要用基类指针指向派生类对象?

在基类与派生类之间,有一个规定:派生类对象的地址可以赋给指向基类对象的指针变量(简称基类指针),即基类指针也可以指向派生类对象。为什么有这一规定呢?因为它可以实现多态性【1】,即向不同的对象发送同一个...
  • FlyingBird_SXF
  • FlyingBird_SXF
  • 2014年11月21日 21:29
  • 1790

VS2013编译boost1.55.0 serialization库错误解决办法

最近到boost的官网上看了一下,发现boost又发布了新的版本1.55,点击这里下载。...
  • sloagnidea
  • sloagnidea
  • 2013年12月05日 16:41
  • 1919

C++ NEW的使用及 基类指针转换成派生类指针 及static_cast和dynamic_cast的说明

new的使用1. new() 分配这种类型的一个大小的内存空间,并以括号中的值来初始化这个变量; 2. new[] 分配这种类型的n个大小的内存空间,并用默认构造函数来初始化这些变量; 3. 当使用n...
  • xiven
  • xiven
  • 2010年03月28日 15:21
  • 5221

将基类指针赋给派生类的问题

将派生类地址赋给基类指针,也就是基类指针指派生类对象,也就是我们平时说的多态 但是反过来的时候,必须经过强制类型转换才可以编译通过, 下来直接代码: #include usingnamespa...
  • LaoJiu_
  • LaoJiu_
  • 2017年05月31日 18:57
  • 541

boost中serialization库对unordered_map支持

很遗憾,serialization库对boost的unordered_map不支持,只能自己实现了,添加如下头文件到工程中吧 /*******************************...
  • neofung
  • neofung
  • 2011年11月18日 18:45
  • 1951

畅游C++ Boost Serialization 序列化

畅游C++ Boost Serialization 序列化。使用案例详细了解Boost::Serialization存储C++对象。...
  • qq2399431200
  • qq2399431200
  • 2015年05月10日 17:27
  • 2066

C++中使用基类指针调用派生类中定义的方法

我们需要告诉傻傻的编译器,基类的指针实际上指向了派生类,可以通过这个指针调用派生类的方法。而告诉编译器这个信息的途径,就是dynamic_cast...
  • u012515915
  • u012515915
  • 2016年05月24日 22:17
  • 1274
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:boost::serialization 用基类指针转存派生类(错误多多,一波三折)
举报原因:
原因补充:

(最多只允许输入30个字)