2014-02-22 2 views
1

부스트 :: 직렬화를 사용하여 일부 데이터를 직렬화 할 때 발생하는 문제를 해결하기 위해 지난 몇 주간 힘들어했습니다.boost :: serialization - 일반 속성/기능 컨테이너에서 파생 된 클래스 직렬화

나는 작업중인 프로젝트에 클라이언트/서버 아키텍처를 사용하는 탭 편집기를 구현하려고합니다. 현재의 설계는 다음과 같이 작동

  • DerivedTab는베이스 클래스에서 확장합니다. (이 예제 질문에서는 DerivedTab 클래스의 예제를 포함하지 않기로 선택했습니다.).

  • 클래스는 AttributeContainer에게 문자열의지도 * AttributeBase에 속성 이름을 포함 클래스를 확장합니다.

  • 속성는 AttributeBase 연장되는 템플릿 클래스이다. 이것은 임의의 구체적인 데이터 유형을 값으로 유지할 수있는 일반 데이터 유형으로 사용하기위한 것입니다.

  • 그리고 마침내, 가 네트워크 연결을 통해 직렬화 할 수있는 개체가 따라야하는 계약을 식별하기 위해 기본 오브젝트 유형으로 사용되는 순수 추상 기본 클래스입니다 NetworkSerializable에서 파생 AttributeBase.

이 모든 것이 내 응용 프로그램에 정적으로 링크 된 라이브러리로 컴파일됩니다. 보시다시피, 간접적으로 진행되는 간접적 인 문제가 있으며 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

가능한 중복 [? Boost.serialize으로 파생 된 템플릿 클래스를 직렬화하는 방법 (http://stackoverflow.com/questions/1332602 : 여기

은 당신의 코드를 기반으로 작업을 단일 파일 예제/how-to-serialize-derived-template-classes-with-boost-serialize) –

+0

다음 번에 예제를 그대로 사용하십시오. SSCCE를 줄이면 위험을 안고있을뿐만 아니라 코드 장벽을 극복하기 위해 임의의 낯선 사람이 필요하지 않습니다. – sehe

답변

1

요약하면 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); 
+0

그게 바로 문제였습니다. 나는 적절한 시나리오를 설명하는 데 적절한 매크로가 있는지 확인하는 데 너무 빠져서 순수 추상 기본 클래스를 갖는 나의 전략이 NetworkSerializable define 클래스의 파생 클래스를 보장한다고 생각조차하지 않았다. 발행물. 이것을 지적 해 주셔서 고맙습니다 !!! ** 이야기의 도덕은 boost :: serialization을 사용할 때, :: serialize 메서드가 가상으로 만들어서는 안됩니다. ** 위의 중복으로 표시된 게시물을 참조하고 구현을 가이드로 시도했습니다. 분명히 나는 ​​뭔가를 간과했다. 다시 한 번 감사드립니다! – user3317522

+0

문제가 해결되어 기쁩니다. 답변을 수락하는 것을 고려하십시오;) –

관련 문제