2014-02-22 30 views
1

我一直在努力解決我在使用boost :: serialization序列化一些數據時遇到的問題。boost :: serialization - 序列化從通用屬性/特徵容器派生的類

我試圖實現一個選項卡式編輯器,利用客戶端/服務器體系結構爲我正在進行的項目。目前的設計是這樣的:

  • DerivedTab從基標籤類擴展。 (對於這個示例問題,我選擇不包含DerivedTab類的示例。)。

  • 標籤類擴展AttributeContainer類,其中包含地圖的字符串的屬性名稱AttributeBase *。

  • 屬性是延伸AttributeBase一個模板類。它旨在用作通用數據類型,可以保存任何具體數據類型的值。

  • 最後,AttributeBaseNetworkSerializable它是用作一個基礎對象類型,以確定可通過網絡連接被序列化的對象必須按照合同純抽象基類派生的。

所有這些都被編譯成一個庫,然後靜態鏈接到我的主應用程序。正如你所看到的那樣,有很多間接方向正在進行,並且我試圖用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 

有相當多的代碼在這裏的人消化,所以我會很感激如果任何人都可以提供任何我可能沿着boost序列化路徑偏離的見解。

+0

可能重複[?如何序列化派生模板類與Boost.serialize(http://stackoverflow.com/questions/1332602/how-to-serialize-derived-template-classes-with-boost-serialize) –

+0

下次,請繼續關注你的例子。在減少到SSCCE時,你不僅可能冒險自己發現問題,而且你也不需要隨機的陌生人來處理代碼。 – sehe

回答

1

簡而言之:您的serialize成員函數應該是而不是是虛擬的。讓他們虛擬結果static_cast<AttributeContainer*>(this)->serialize(...)boost::serialization::base_objectTab::serialize_attributesstatic_cast<AttributeContainer*>(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); 
+0

這正是問題所在。我認爲我太擔心確保我有適當的宏來描述正確的場景,甚至不認爲我的擁有純抽象基類的策略確保NetworkSerializable define :: serialize()的派生類將是問題。非常感謝您指出這一點! **故事的道德是使用boost :: serialization,:: serialize方法不應該是虛擬的。** 我曾引用上面標記爲重複的帖子,並試圖將其實現作爲指導。顯然我忽略了一些東西。再次感謝! – user3317522

+0

我很高興你的問題解決了。請考慮接受答案;) –

相關問題