2015-06-02 4 views
5

Я попытался предоставить геттеры класса A для моего нечлена serialize() Функция `, поскольку доступ к членам из них является закрытым.Получить личные данные для неинтрузивного форсирования сериализации C++

template<typename T> 
class A 
{ 
public: 
    A(const T& id) : m_id(id) {} 
    T& getRef() { return m_id; } // not giving good results 
    T getId() { return m_id; } // not giving good results 
    const T& getRef() const { return m_id; } // not giving good results 
private: // I would like to keep it private 
    T m_id; 
} 

namespace boost { namespace serialization { 

template<class Archive,typename T> 
void serialize(Archive &ar, A &a, const unsigned int version) 
{ 
    // ar &BOOST_SERIALIZATION_NVP(a.m_id); // I would like to avoid that it works if m_id is public 
    ar &BOOST_SERIALIZATION_NVP(a.GetRef()); // I want this ! 
} 

}} 

// and later I use 
std::ofstream ofs("test.xml"); 
boost::archive::xml_oarchive oa(ofs); 
A<int> a(42); 
oa << BOOST_SERIALIZATION_NVP(a); 

К сожалению, исполнение твердит мне uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name, когда я пытаюсь использовать методы получения либо GetRef() или GetId().
Он хорошо работает, если я получаю доступ к m_id, когда он является общедоступным.

Есть ли хорошие способы сделать это?

ответ

11
  1. Вы можете использовать старомодные хорошие друзья:

    Live On Coliru

    template <typename T> 
    class A { 
        public: 
        A(const T &id) : m_id(id) {} 
        private: 
        template <typename Ar, typename U> friend void boost::serialization::serialize(Ar&,A<U>&,const unsigned); 
        T m_id; 
    }; 
    
    namespace boost { 
    namespace serialization { 
        template <class Archive, typename T> 
        void serialize(Archive &ar, A<T> &a, const unsigned int) 
        { 
         ar & BOOST_SERIALIZATION_NVP(a.m_id); 
        } 
    } 
    } 
    

  2. Вы можете использовать getRef() подход. Это

    • не требует друзей (менее навязчивым)
    • требует make_nvp (потому что вы не можете использовать a.getRef() в качестве имени XML-элемента

    К сожалению, имея перерыв инкапсуляцию ссылка геттер в что я предпочитаю иметь m_id общественность, в первую очередь, вместо этого.

    Live On Coliru

    template <typename T> 
    class A { 
    public: 
        A(const T &id) : m_id(id) {} 
    
        T& getRef()    { return m_id; } 
        T const& getRef() const { return m_id; } 
    private: 
        T m_id; 
    }; 
    
    namespace boost { 
    namespace serialization { 
        template <class Archive, typename T> 
        void serialize(Archive &ar, A<T> &a, const unsigned int) 
        { 
         ar & boost::serialization::make_nvp("m_id", a.getRef()); 
        } 
    } 
    } 
    

    Бонусные баллы:

  3. Вы можете использовать '' Pimpl стиль структуры. Вы можете вперед объявить внутри-структуру A<>:

    template <typename T> 
    class A { 
    public: 
        struct access; 
    
        A(const T &id) : m_id(id) {} 
    private: 
        T m_id; 
    }; 
    

    Это менее навязчивым, чем getRef() подхода, который просто ломает Инкапсуляцию всего пути.Теперь вы можете скрыть частный доступ внутри этого класса:

    namespace boost { 
    namespace serialization { 
        template <class Archive, typename T> 
        void serialize(Archive &ar, A<T> &a, const unsigned int version) 
        { 
         A<T>::access::serialize(ar, a, version); 
        } 
    } 
    } 
    

    Конечно вам все еще нужно реализовать, но это может быть сделано в отдельном заголовке и не влияет класса А <> (или любой из его специализации) на всех:

    template <typename T> 
    struct A<T>::access { 
        template <class Archive> 
        static void serialize(Archive &ar, A<T> &a, const unsigned int) { 
         ar & BOOST_SERIALIZATION_NVP(a.m_id); 
        } 
    }; 
    

    Посмотри Live On Coliru а

+0

Добавлен "Бест-оф-и-миры" подход, который не нарушает инкапсуляцию: ** [Live On Coliru] (http://coliru.stacked-crooked.com/a/5d76b1aa22076a77) **. – sehe

+2

ничего себе. это действительно хороший ответ, предлагающий различные решения со своими плюсами и минусами. Ровно то, что я прыгал;). Спасибо ! Жаль, что я не могу голосовать дважды ... Я дам 1/и 3 ​​/ попытку! – coincoin

+1

Как всегда, полный отличный ответ. Кроме того, не прерывая инкапсуляцию и, вероятно, полное нарушение доверия, [этот подход демонстрирует] (http://coliru.stacked-crooked.com/a/4424c219ee37aa20), сериализуя частные переменные-члены. Насколько я могу судить, это соответствует спецификации. Мне, к сожалению, пришлось использовать это при работе с сторонними библиотеками.): –

0

Просто для получения дополнительной информации: В Для того чтобы получить первое решение от sehe работы:

Вам нужен вперед decleration метода друзей, как это:

// Boost 
#include <boost/serialization/access.hpp> 

class ClassB; 

namespace boost{ 
namespace serialization { 
    template <typename Ar> void serialize(Ar&,ClassB&,const unsigned); 
} 
} 

class ClassB: public ClassA{ 

private: 
    template <typename Ar> friend void boost::serialization::serialize(Ar&,ClassA&,const unsigned); 
public: 
    ClassA(); 
    virtual ~ClassA(); 
}; 

Взял меня некоторое время, чтобы заставить его работать.

Приветствия

+0

На самом деле, чтобы заставить этот образец работать, просто _ щелкните по ссылке, которая говорит_ ** [Live On Coliru] (http://coliru.stacked-crooked.com/a/1a0004c419ea0e37) ** и убедитесь, что вам не нужно форвардная декларация – sehe

Смежные вопросы