C++ 序列化-序列化从泛型属性/功能容器派生的类

C++ 序列化-序列化从泛型属性/功能容器派生的类,c++,templates,serialization,boost,containers,C++,Templates,Serialization,Boost,Containers,在过去的几周里,我一直在努力解决使用boost::serialization序列化某些数据时遇到的问题 我正在尝试实现一个选项卡式编辑器,它利用客户机/服务器体系结构来处理我正在处理的项目。当前设计的工作原理如下: DerivedTab从基本选项卡扩展而来。(对于这个示例问题,我选择不包括DerivedTab类的示例。) 选项卡类扩展了AttributeContainer类,该类包含字符串属性名称到AttributeBase*的映射 属性是扩展属性库的模板类。它打算用作一种通用数据类型,可以保

在过去的几周里,我一直在努力解决使用boost::serialization序列化某些数据时遇到的问题

我正在尝试实现一个选项卡式编辑器,它利用客户机/服务器体系结构来处理我正在处理的项目。当前设计的工作原理如下:

  • DerivedTab从基本选项卡扩展而来。(对于这个示例问题,我选择不包括DerivedTab类的示例。)

  • 选项卡类扩展了AttributeContainer类,该类包含字符串属性名称到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::serialize  
AttributeContainer::serialize  
Attribute::serialize  
AttributeBase::serialize  
Attribute::serialize  
AttributeBase::serialize  

这里有很多代码需要消化,因此如果有人能够提供我可能在boost序列化路径上迷失的任何见解,我将非常感激。

简而言之:您的
序列化
成员函数应该而不是虚拟的。通过调用
boost::serialization::base_object
Tab::serialize_attributes
内部创建的
static_cast(this)->serialize(…)
,通过虚拟函数分派返回
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);
名称空间串行\u测试
{
使用名称空间std;
类NetworkSerializable{
好友类boost::serialization::access;
公众:
typedef std::shared_ptr NetworkSerializablePtr;
NetworkSerializable(){};
受保护的:
//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_序列化_假设_抽象(NetworkSerializable);
类AttributeBase:公用网络可序列化{
好友类属性容器;
好友类boost::serialization::access;
公众:
AttributeBase(){}
虚拟~AttributeBase(){}
受保护的:
std::string _name;
std::字符串_描述;
模板
内联void序列化_属性(存档&ar,常量unsigned int版本){
ar&boost::serialization::make_nvp(“名称”,_名称);
ar&boost::序列化::生成nvp(“描述”,描述);
}
void序列化(boost::archive::text\u oarchive&oa,const unsigned int版本){

不可能重复的请,下次,把你的例子切中要害。在简化为SSCCE时,你不仅要冒发现问题的风险你自己,但你也不需要随机陌生人来处理代码墙。这正是问题所在。我想我太专注于确保我有合适的宏来描述合适的场景,甚至没有想到我拥有纯抽象基类的策略可以确保NetworkSerializable的派生类定义::序列化()这就是问题所在。非常感谢您指出这一点!!!这个故事的寓意是,当使用boost::serialization时,::serialization方法不应被虚拟化。我引用了上面标记为重复的帖子,并尝试将其实现作为指南。显然我忽略了一些内容。再次感谢!我很高兴您的问题得到解决。请继续赛德接受答案;)
#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__
#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);
}
#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__
#include "Attribute.h"

BOOST_CLASS_EXPORT_IMPLEMENT(test::Attribute<bool>);
BOOST_CLASS_EXPORT_IMPLEMENT(test::Attribute<std::string>);

using namespace test;
#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__
#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  
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);