获取非侵入式升压序列化 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<>
中转发声明一个结构:
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++ 的私有数据成员的主要内容,如果未能解决你的问题,请参考以下文章