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

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

I have tried providing getters of class A for my non-member serialize() function` since accessing from members is private.

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

不幸的是,当我尝试使用 getter GetRef()GetId().
如果我在公开时直接访问 m_id,则效果很好.

Unfortunately the execution keeps telling me uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name when I try to use getters either GetRef()or GetId().
It works well if I access directly to m_id when it is public.

有什么好的方法吗?

推荐答案

  1. 你可以使用老派的好朋友:

  1. You can use good old-fashioned friends:

生活在 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);
    }
}
}


  • 您可以使用 getRef() 方法.这个

    • 不需要朋友(较少打扰)
    • 需要 make_nvp(因为你不能使用 a.getRef() 作为 XML 元素名称
    • requires no friends (less intrusive)
    • requires make_nvp (because you can't use a.getRef() as an XML element name

    遗憾的是,引用 getter 以一种可怕的方式破坏了封装.我个人更喜欢首先公开 m_id.

    Sadly, having the reference getter break encapsulation in a horrific way. I'd personally prefer to have m_id public in the first place, instead.

    生活在 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());
        }
    }
    }
    

    奖励积分:

  • 您可以使用pimpl"风格的结构.您可以在 A<> 中转发声明一个结构体:

    Bonus points:

  • You can use a 'pimpl' style struct. You can forward declare a struct inside A<>:

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

    这比 getRef() 方法的侵入性要小,后者只是完全破坏了封装.现在,您可以在该类中隐藏私有访问权限:

    That's less intrusive than the getRef() approach which simply breaks encapsulation all the way. Now, you can hide the private access inside this class:

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

    当然,您仍然需要实现它,但这可以在单独的标题中完成,并且根本不会影响类 A<>(或其任何特化):

    Of course you still need to implement it, but this can be done in a separate header and doesn't influence class A<> (or any of its specializations) at all:

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

    看看它生活在 Coliru 以及p>

  • 相关文章