过去几周我一直在努力解决使用boost :: serialization序列化一些数据时遇到的问题。
我正在尝试实现一个标签式编辑器,该编辑器利用客户端/服务器架构来处理我正在进行的项目。目前的设计是这样的:
DerivedTab 从基础标签类扩展而来。 (对于此示例问题,我选择不包含DerivedTab类的示例。)。
标签类扩展 AttributeContainer 类,其中包含字符串属性名称的映射到AttributeBase *。
属性是一个模板化的类,它扩展了 AttributeBase 。它旨在用作可以保存任何具体数据类型值的通用数据类型。
最后, AttributeBase 派生自 NetworkSerializable ,它是一个纯抽象基类,用作基础对象类型,用于标识可以序列化的对象的合同必须通过网络连接。
所有这些都被编译成一个库,然后静态链接到我的主应用程序中。正如你所看到的,有很多间接性存在,而且我正在尝试使用boost :: serialization进行序列化。我已经删除了与使这些类序列化无关的所有其他代码。但是,示例代码仍然很长。
main.cpp中:
#include <sstream>
#include <boost/archive/text_iarchive.hpp>
#include <boost/archive/text_oarchive.hpp>
#include "Tab.h"
using namespace test;
int main(int argc, char **argv)
{
std::ostringstream oarchiveStream;
boost::archive::text_oarchive outputArchive(oarchiveStream);
Tab* tab = new Tab("temp");
bool tempBool = true;
tab->RegisterAttribute("tempBool", "a temp boolean", &tempBool);
std::string tempString("1234");
tab->RegisterAttribute("tempString", "a temp string", &tempString);
outputArchive << tab;
}
Tab.h:
#ifndef __TAB_H__
#define __TAB_H__
#include "AttributeContainer.h"
#include <boost/serialization/base_object.hpp>
namespace test
{
class Tab : public AttributeContainer
{
friend class boost::serialization::access;
public:
Tab(const std::string tabName);
virtual ~Tab();
protected:
Tab();
template<class archive>
inline void serialize_attributes(archive& ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AttributeContainer);
ar & boost::serialization::make_nvp("TabName", _tabName);
}
virtual void serialize(boost::archive::text_oarchive& oa, const unsigned int version);
virtual void serialize(boost::archive::text_iarchive& ia, const unsigned int version);
private:
std::string _tabName;
};
} // namespace test
BOOST_CLASS_EXPORT_KEY(test::Tab);
#endif // #ifndef __TAB_H__
Tab.cpp:
#include "Tab.h"
BOOST_CLASS_EXPORT_IMPLEMENT(test::Tab);
using namespace test;
Tab::Tab(const std::string tabName) : _tabName(tabName)
{
}
Tab::~Tab()
{
}
Tab::Tab() : _tabName("")
{
}
void Tab::serialize(boost::archive::text_oarchive& oa, const unsigned int version)
{
std::cout << "Tab::serialize" << std::endl;
serialize_attributes(oa, version);
}
void Tab::serialize(boost::archive::text_iarchive& ia, const unsigned int version)
{
serialize_attributes(ia, version);
}
AttributeContainer.h:
#ifndef __ATTRIBUTE_CONTAINER_H__
#define __ATTRIBUTE_CONTAINER_H__
#include "NetworkSerializable.h"
#include <boost/serialization/map.hpp>
#include "Attribute.h"
namespace test
{
class AttributeContainer : public NetworkSerializable
{
friend class boost::serialization::access;
public:
std::map<std::string, AttributeBase*> _attributes;
AttributeContainer() {};
virtual ~AttributeContainer() {};
template <typename _T>
void RegisterAttribute(const std::string& name, const std::string& description, _T* var)
{
std::map<std::string, AttributeBase*>::const_iterator pos;
if ( (pos = _attributes.find(name)) == _attributes.end() )
{
Attribute<_T>* attribute = new Attribute<_T>(name, description, var);
_attributes.insert(std::map<std::string, AttributeBase*>::value_type(name, attribute));
}
};
template <class archive>
inline void serialize_attributes(archive& ar, const unsigned int version)
{
ar & _attributes;
};
virtual void serialize(boost::archive::text_oarchive& oa, const unsigned int version);
virtual void serialize(boost::archive::text_iarchive& ia, const unsigned int version);
}; // end class AtributeContainer
} // end namespace test
BOOST_CLASS_EXPORT_KEY(test::AttributeContainer);
#endif // #ifndef __ATTRIBUTE_CONTAINER_H__
AttributeContainer.cpp:
#include "AttributeContainer.h"
BOOST_CLASS_EXPORT_IMPLEMENT(test::AttributeContainer);
using namespace test;
void AttributeContainer::serialize(boost::archive::text_oarchive& oa, const unsigned int version)
{
std::cout << "AttributeContainer::serialize" << std::endl;
serialize_attributes(oa, version);
}
void AttributeContainer::serialize(boost::archive::text_iarchive& ia, const unsigned int version)
{
serialize_attributes(ia, version);
}
Attribute.h:
#ifndef __ATTRIBUTE_H__
#define __ATTRIBUTE_H__
#include "AttributeBase.h"
namespace test
{
template <typename _T>
class Attribute : public AttributeBase
{
friend class AttributeContainer;
friend class boost::serialization::access;
public:
typedef _T AttributeType;
Attribute() : _data(0) {}
Attribute(const std::string& name, const std::string& description, AttributeType* var) : _data(var)
{
_name = name;
_description = description;
}
virtual ~Attribute() {}
protected:
AttributeType* _data;
template <class archive>
inline void serialize_base(archive& ar, const unsigned int version)
{
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AttributeBase);
ar & boost::serialization::make_nvp("Value", *_data);
}
virtual void serialize(boost::archive::text_oarchive& oa, const unsigned int version)
{
std::cout << "Attribute::serialize" << std::endl;
serialize_base(oa, version);
}
virtual void serialize(boost::archive::text_iarchive& ia, const unsigned int version)
{
serialize_base(ia, version);
}
};
} // namespace test
BOOST_CLASS_EXPORT_KEY(test::Attribute<bool>);
BOOST_CLASS_EXPORT_KEY(test::Attribute<std::string>);
#endif // #ifndef __ATRIBUTE_H__
Attribute.cpp:
#include "Attribute.h"
BOOST_CLASS_EXPORT_IMPLEMENT(test::Attribute<bool>);
BOOST_CLASS_EXPORT_IMPLEMENT(test::Attribute<std::string>);
using namespace test;
AttributeBase.h:
#ifndef __ATTRIBUTE_BASE_H__
#define __ATTRIBUTE_BASE_H__
#include "NetworkSerializable.h"
#include <string>
namespace test
{
class AttributeBase : public NetworkSerializable
{
friend class AttributeContainer;
friend class boost::serialization::access;
public:
AttributeBase();
virtual ~AttributeBase();
protected:
AttributeBase& operator=(const AttributeBase&);
AttributeBase(const AttributeBase&);
protected:
std::string _name;
std::string _description;
template<class archive>
inline void serialize_attributes(archive& ar, const unsigned int version)
{
ar & boost::serialization::make_nvp("Name", _name);
ar & boost::serialization::make_nvp("Description", _description);
}
virtual void serialize(boost::archive::text_oarchive& oa, const unsigned int version);
virtual void serialize(boost::archive::text_iarchive& ia, const unsigned int version);
}; // end class AttributeBase
} // end namespace test
BOOST_SERIALIZATION_ASSUME_ABSTRACT(test::AttributeBase);
BOOST_CLASS_EXPORT_KEY(test::AttributeBase);
#endif // #ifndef __ATTRIBUTE_BASE_H__
NetworkSerializable.h:
#ifndef __NETWORK_SERIALIZABLE_H__
#define __NETWORK_SERIALIZABLE_H__
#pragma warning(disable:4244)
#include <boost/shared_ptr.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/export.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
namespace test
{
class NetworkSerializable
{
friend class boost::serialization::access;
public:
typedef std::shared_ptr<NetworkSerializable> NetworkSerializablePtr;
NetworkSerializable() {};
protected:
virtual void serialize(boost::archive::text_oarchive& oa, const unsigned int version) = 0;
virtual void serialize(boost::archive::text_iarchive& ia, const unsigned int version) = 0;
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(NetworkSerializable);
} // namespace test
#endif // #ifndef __NETWORK_SERIALIZABLE_H__
我试图让代码尽可能简洁明了,以充分展示我遇到的问题。
提供的代码的输出是:
Tab::serialize
Tab::serialize
当输出应为:
Tab::serialize
AttributeContainer::serialize
Attribute::serialize
AttributeBase::serialize
Attribute::serialize
AttributeBase::serialize
这里有相当多的代码供有人消化,所以如果有人能提供任何我可能已经偏离了升级序列化路径的洞察力,我会非常感激。
答案 0 :(得分:1)
简而言之:您的serialize
会员功能不应该是虚拟的。将它们设为虚拟会导致static_cast<AttributeContainer*>(this)->serialize(...)
内的boost::serialization::base_object
调用Tab::serialize_attributes
,通过虚拟函数调度重新登陆Tab::serialize
。
这是一个基于代码的工作单文件示例:
namespace serial_test
{
using namespace std;
class NetworkSerializable {
friend class boost::serialization::access;
public:
typedef std::shared_ptr<NetworkSerializable> NetworkSerializablePtr;
NetworkSerializable() {};
protected:
// void serialize(boost::archive::text_oarchive& oa, const unsigned int version) = 0;
// void serialize(boost::archive::text_iarchive& ia, const unsigned int version) = 0;
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(NetworkSerializable);
class AttributeBase : public NetworkSerializable {
friend class AttributeContainer;
friend class boost::serialization::access;
public:
AttributeBase() {}
virtual ~AttributeBase() {}
protected:
std::string _name;
std::string _description;
template<class archive>
inline void serialize_attributes(archive& ar, const unsigned int version) {
ar & boost::serialization::make_nvp("Name", _name);
ar & boost::serialization::make_nvp("Description", _description);
}
void serialize(boost::archive::text_oarchive& oa, const unsigned int version) {
cout << "AttributeBase::serialize" << endl;
serialize_attributes(oa, version);
}
void serialize(boost::archive::text_iarchive& ia, const unsigned int version) {
serialize_attributes(ia, version);
}
}; // end class AttributeBase
template <typename _T>
class Attribute : public AttributeBase {
friend class AttributeContainer;
friend class boost::serialization::access;
public:
typedef _T AttributeType;
Attribute() : _data(0) {}
Attribute(const std::string& name, const std::string& description, AttributeType* var) : _data(var) {
_name = name;
_description = description;
}
virtual ~Attribute() {}
protected:
AttributeType* _data;
template <class archive>
void serialize_base(archive& ar, const unsigned int version) {
ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AttributeBase);
ar & boost::serialization::make_nvp("Value", *_data);
}
void serialize(boost::archive::text_oarchive& oa, const unsigned int version) {
std::cout << "Attribute::serialize" << std::endl;
serialize_base(oa, version);
}
void serialize(boost::archive::text_iarchive& ia, const unsigned int version) {
serialize_base(ia, version);
}
};
class AttributeContainer : public NetworkSerializable {
friend class boost::serialization::access;
public:
std::map<std::string, AttributeBase*> _attributes;
AttributeContainer() {};
virtual ~AttributeContainer() {};
template <typename _T>
void RegisterAttribute(const std::string& name, const std::string& description, _T* var) {
std::map<std::string, AttributeBase*>::const_iterator pos;
if ( (pos = _attributes.find(name)) == _attributes.end() ) {
Attribute<_T>* attribute = new Attribute<_T>(name, description, var);
_attributes.insert(std::map<std::string, AttributeBase*>::value_type(name, attribute));
}
};
template <class archive>
void serialize_attributes(archive& ar, const unsigned int version) {
ar & _attributes;
};
void serialize(boost::archive::text_oarchive& oa, const unsigned int version) {
std::cout << "AttributeContainer::serialize" << std::endl;
serialize_attributes(oa, version);
}
void serialize(boost::archive::text_iarchive& ia, const unsigned int version) {
serialize_attributes(ia, version);
}
}; // end class AtributeContainer
class Tab : public AttributeContainer {
friend class boost::serialization::access;
public:
Tab(const std::string tabName)
: _tabName(tabName) {}
virtual ~Tab() {}
protected:
Tab()
: _tabName("") {}
template<class archive>
inline void serialize_attributes(archive& ar, const unsigned int version) {
// ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(AttributeContainer);
ar & boost::serialization::base_object<AttributeContainer>(*this);
ar & boost::serialization::make_nvp("TabName", _tabName);
}
void serialize(boost::archive::text_oarchive& oa, const unsigned int version) {
std::cout << "Tab::serialize" << std::endl;
serialize_attributes(oa, version);
}
void serialize(boost::archive::text_iarchive& ia, const unsigned int version) {
serialize_attributes(ia, version);
}
private:
std::string _tabName;
};
void test() {
std::ostringstream oarchiveStream;
boost::archive::text_oarchive outputArchive(oarchiveStream);
Tab* tab = new Tab("temp");
bool tempBool = true;
tab->RegisterAttribute("tempBool", "a temp boolean", &tempBool);
std::string tempString("1234");
tab->RegisterAttribute("tempString", "a temp string", &tempString);
outputArchive << tab;
}
} // namespace serial_test
BOOST_SERIALIZATION_ASSUME_ABSTRACT(serial_test::AttributeBase);
BOOST_CLASS_EXPORT_KEY(serial_test::AttributeBase);
BOOST_CLASS_EXPORT_KEY(serial_test::Attribute<bool>);
BOOST_CLASS_EXPORT_KEY(serial_test::Attribute<string>);
BOOST_CLASS_EXPORT_IMPLEMENT(serial_test::Attribute<bool>);
BOOST_CLASS_EXPORT_IMPLEMENT(serial_test::Attribute<string>);
BOOST_CLASS_EXPORT_KEY(serial_test::Tab);
BOOST_CLASS_EXPORT_IMPLEMENT(serial_test::Tab);