boost :: serialization - 序列化从通用属性/特征容器派生的类

时间:2014-02-22 03:20:35

标签: c++ templates serialization boost containers

过去几周我一直在努力解决使用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  

这里有相当多的代码供有人消化,所以如果有人能提供任何我可能已经偏离了升级序列化路径的洞察力,我会非常感激。

1 个答案:

答案 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);