获取非侵入式boost序列化C++的私有数据成员

coi*_*oin 8 c++ serialization boost boost-serialization

我尝试A为我的非成员serialize()函数提供类的getter,因为从成员访问是私有的.

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);
Run Code Online (Sandbox Code Playgroud)

不幸的是,执行不断告诉我uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name,当我尝试使用干将无论是GetRef()GetId().
如果我直接访问m_id它是公开的,它的效果很好.

这样做有什么好方法吗?

seh*_*ehe 13

  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);
        }
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  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());
        }
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    奖励积分:

  3. 您可以使用'pimpl'样式结构.你可以在里面声明一个struct A<>:

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

    这比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);
        }
    }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    当然你仍然需要实现它,但是这可以在一个单独的头文件中完成,并且根本不会影响A <>(或它的任何特化):

    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);
        }
    };
    
    Run Code Online (Sandbox Code Playgroud)

    看到它住在Coliru以及

  • 哇.这是一个非常好的答案,提供不同的解决方案的优点和缺点.我正在跳跃的是什么;).谢谢 !太糟糕了我不能投两次......我会给1/3 /一次尝试! (2认同)