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

Posted

技术标签:

【中文标题】获取非侵入式升压序列化 C++ 的私有数据成员【英文标题】:Get private data members for non intrusive boost serialization C++ 【发布时间】:2015-06-02 11:32:34 【问题描述】:

我已尝试为我的非成员 serialize() 函数提供类 A 的 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);

不幸的是,当我尝试使用吸气剂GetRef()GetId()时,执行一直告诉我uncaught exception of type boost::archive::xml_archive_exception - Invalid XML tag name。 如果我在公开时直接访问m_id,效果会很好。

有什么好的方法吗?

【问题讨论】:

【参考方案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);
        
    
    
    

    您可以使用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());
        
    
    
    

    奖励积分:

    您可以使用“pimpl”样式的结构。您可以在A&lt;&gt; 中转发声明一个结构:

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

    这比getRef() 方法的侵入性要小,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 类(或其任何特化):

    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

【讨论】:

添加了一种不会破坏封装的“两全其美”的方法:Live On Coliru 哇。这是一个非常好的答案,提供了不同的解决方案及其优缺点。正是我想要的;)。谢谢 !太糟糕了,我不能投票两次...我会尝试 1/ 和 3/ ! 一如既往,一个完整的好答案。此外,虽然没有破坏封装,并且可能完全违反信任,this approach demonstrates 序列化私有成员变量。据我所知,它符合规范。很遗憾,在处理第三方库时,我不得不使用它。 ): 感谢 Tanner 的解决方案,我会看看!【参考方案2】:

仅供参考:为了让 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();
;

我花了一段时间才让它工作。

干杯

【讨论】:

实际上,要使该示例正常工作,您只需单击显示 Live On Coliru 的链接,然后您就不需要转发了声明【参考方案3】:

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

该解决方案需要两阶段查找和/或依赖于参数的查找。不幸的是,MSVC 还没有完全支持这一点。

在 VS Community 2019 16.1.6 中使用 boost 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

【讨论】:

以上是关于获取非侵入式升压序列化 C++ 的私有数据成员的主要内容,如果未能解决你的问题,请参考以下文章

红外远程抄表无线 远程智能读表 国网电表非侵入式采集

C++设计模式Singleton的侵入式和声明式

非侵入式获取Context进行SDK初始化

C++ 模板工厂构造函数/反序列化

第六章:侵入式服务治理

基于SpringBoot轻量非侵入式数据库数据告警器