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

时间:2015-06-02 11:32:35

标签: c++ serialization boost boost-serialization

我尝试为我的非成员LD_PRELOAD函数提供类A的getter,因为从成员访问是私有的。

serialize()

不幸的是,当我尝试使用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的getter时,执行会一直告诉我GetRef()。 如果我公开时直接访问GetId(),它的效果很好。

有没有很好的方法呢?

3 个答案:

答案 0 :(得分:12)

  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元素名称
      

    可悲的是,让参考getter以可怕的方式打破封装。我个人更喜欢首先公开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);
        }
    }
    }
    

    当然你还需要实现它,但这可以在一个单独的标题中完成,并且不会影响A类&lt;&gt; (或其任何专业):

    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

答案 1 :(得分:1)

仅供参考:为了获得 sehe 工作的第一个解决方案:

你需要这样的朋友方法的前进去除

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

让我花一点时间让它发挥作用。

干杯

答案 2 :(得分:0)

sehe第一个解决方案的补充信息:

该解决方案需要两阶段查找和/或与参数相关的查找。不幸的是,MSVC尚未完全支持这一点。

在VS Community 2019 16.1.6中以1.70进行编译会导致模糊的错误:

Error   C2063    'boost::serialization::serialize': not a function

即使通过/ permissive-标志启用了一致性模式,并且已选择最新的语言标准/ std :: c ++ latest,如this MSVC Blog Post中所述。

在朋友声明中添加类型名称限定符即可解决此问题:

template <typename Ar, typename U> friend void boost::serialization::serialize(typename Ar&, A<U>&, const unsigned);

更令人沮丧的

如果类A不是模板化类,则无论哪种方式都不会起作用,与上述错误相同... 示例代码:http://coliru.stacked-crooked.com/a/ecfbb39d5975d753