2015-06-02 19 views
5

Próbowałem dostarczać pobierające klasy klasy A dla mojej nieczłonkowskiej funkcji serialize(), ponieważ dostęp do członków jest prywatny.Uzyskaj prywatnych członków danych dla nieinwazyjnej serializacji wzmocnienia C++

Niestety wykonanie powtarza mi uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name gdy próbuję użyć pobierające albo GetRef() lub GetId().
Działa dobrze, jeśli mam bezpośredni dostęp do m_id, gdy jest on publiczny.

Czy są na to dobre sposoby?

Odpowiedz

11
  1. można wykorzystywać dobre staromodne przyjaciół

    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. Można użyć podejście getRef(). Ten

    • wymaga żadnych znajomych (mniej inwazyjne)
    • wymaga make_nvp (bo nie można używać a.getRef() jako nazwy elementu XML

    Niestety, posiadające przerwy getter odniesienia enkapsulacji w A straszny sposób.Id osobiście wolałbym zamiast tego publiczną 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()); 
        } 
    } 
    } 
    

    punkty bonusowe:

  3. można użyć 'pimpl' styl struct. Można do przodu zadeklarować struct wewnątrz A<>:

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

    to mniej inwazyjne niż podejścia getRef() który po prostu łamie enkapsulacji całą drogę.Teraz można ukryć prywatny dostęp do wnętrza tej klasie:

    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); 
        } 
    } 
    } 
    

    Oczywiście trzeba jeszcze do jego realizacji, ale można to zrobić w oddzielnym nagłówku i nie wpływa Klasa A <> (lub którykolwiek z jego specjalizacje) we wszystkich:

    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); 
        } 
    }; 
    

    Zobacz Live On Coliru także

+0

dodał podejście "best-of-obie-światy", która nie łamie enkapsulacji: ** [Live On Coliru] (http://coliru.stacked-crooked.com/a/5d76b1aa22076a77) **. – sehe

+2

wow. to naprawdę fajna odpowiedź, oferująca różne rozwiązania z ich zaletami i wadami. Dokładnie to, na co miałem ochotę;). Dziękuję Ci ! Szkoda, nie mogę głosować dwa razy ... dam 1/i 3/a spróbować! – coincoin

+1

Jak zawsze, kompletna wspaniała odpowiedź. Ponadto, nie naruszając hermetyzacji i prawdopodobnie całkowitego naruszenia zaufania [pokazuje to] (http://coliru.stacked-crooked.com/a/4424c219ee37aa20) serializowanie prywatnych zmiennych członków. Jak najlepiej, mogę powiedzieć, że jest zgodny ze specyfikacją. Niestety musiałem użyć tego w kontaktach z bibliotekami stron trzecich.): –

0

Tylko Informacje dodatkowe: W Aby uzyskać pierwsze rozwiązanie z sehe robocza:

Musisz naprzód decleration metody znajomymi tak:

// 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(); 
}; 

Zajęło mi trochę czasu, aby uzyskać jego pracy.

Cheers

+0

Właściwie, aby ta próbka działała, po prostu kliknij link, który mówi: ** [Live On Coliru] (http://coliru.stacked-crooked.com/a/1a0004c419ea0e37) ** i zobacz, że nie potrzebujesz deklaracja terminowa – sehe