促进不同派生的序列化和反序列化类
boost serialization and deserialization for different derived classes
一些class有相同的变量,它们都需要序列化,所以我想定义一个抽象class,它有两个纯虚函数serialize()
和deserialize()
以便这些 classes 可以继承它并覆盖功能。
但是我发现重写的函数都是重复的代码,像下面这样:
void Derived::serialize() {
...
ofstream ofs(file, ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << (*this);
}
void Derived::deserialize() {
...
ifstream ifs(file, ios::binary);
boost::archive::bianry_iarchive ia(ifs);
ia >> (*this);
}
我该如何解决这个问题?
我观察到您将 *this
序列化为 Base&
。因为那不是指针类型,所以您无法反序列化派生类型。这让我怀疑你真正拥有什么样的 class 层次结构。
我展示完整的例子:
- 非虚拟层次结构
- 虚拟层次结构/多态序列化
1。非虚拟层次结构
您可以使用 CRTP 来做一些 取决于派生类型的事情:
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/array.hpp>
#include <fstream>
template <typename Derived> class Base {
public:
void serialize() const
{
//...
std::ofstream ofs(file, std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << as_derived();
}
void deserialize() {
//...
std::ifstream ifs(file, std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
ia >> as_derived();
}
protected:
std::string file = "base.bin";
private:
int base_data = 42;
Derived& as_derived() { return static_cast<Derived&>(*this); } ;
Derived const& as_derived() const { return static_cast<Derived&>(*this); } ;
friend class boost::serialization::access;
template <typename Ar> void serialize(Ar& ar, unsigned)
{
ar
& base_data
& as_derived().common_derived_data
;
}
};
struct Derived1 : Base<Derived1> {
private:
friend class Base;
std::array<float, 30> common_derived_data = {1,1,1,1};
};
struct Derived2 : Base<Derived2> {
private:
friend class Base;
std::array<float, 30> common_derived_data = {2,2,2,2};
};
int main() {
Derived1 x;
Derived2 y;
x.serialize();
system("xxd base.bin");
x.deserialize();
y.serialize();
system("xxd base.bin");
x.deserialize();
}
注:
这不再是虚拟层次结构。多态类型 impose constraints on Boost Serialization。你会想要坚持使用 Boost 方法。也许使用简单的免费函数模板来帮助解决重复代码?
2。虚拟层次结构/多态序列化
示例:
注:
- 序列化必须通过指针
- 序列化必须通过指向 Base 的指针(或者至少与序列化的类型相同,所以 a base class 是唯一有意义的)
- 类型必须注册(或假定为抽象),参见 BOOST_CLASS_EXPORT 等
repeated_serialization_code
函数模板现在是重复序列化代码的所在地。
- 请注意,必须包括
base_object
This
根据调用上下文推导出const/non-const
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/array.hpp>
#include <boost/serialization/export.hpp>
#include <fstream>
class Base {
public:
using Ptr = std::unique_ptr<Base>;
virtual ~Base() = default;
static void serialize(std::string file, Ptr const& ptr)
{
//...
std::ofstream ofs(file, std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << ptr;
}
static Ptr deserialize(std::string file) {
Ptr ptr;
//...
std::ifstream ifs(file, std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
ia >> ptr;
return ptr;
}
protected:
int base_data = 42;
friend class boost::serialization::access;
template <typename Ar> void serialize(Ar& ar, unsigned) { ar& base_data; }
template <typename Ar, typename This>
static inline void repeated_serialization_code(Ar& ar, This& self, unsigned)
{
ar & boost::serialization::base_object<Base>(self)
& self.common_derived_data;
}
};
struct Derived1 : Base {
private:
friend class Mixin;
std::array<float, 30> common_derived_data = {1,1,1,1};
friend class boost::serialization::access;
friend class Base;
template <typename Ar> void serialize(Ar& ar, unsigned v) {
repeated_serialization_code(ar, *this, v);
}
};
struct Derived2 : Base {
private:
friend class Mixin;
std::array<float, 30> common_derived_data = {2,2,2,2};
friend class boost::serialization::access;
friend class Base;
template <typename Ar> void serialize(Ar& ar, unsigned v) {
repeated_serialization_code(ar, *this, v);
}
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Base)
BOOST_CLASS_EXPORT(Derived1)
BOOST_CLASS_EXPORT(Derived2)
int main() {
Base::Ptr x = std::make_unique<Derived1>();
Base::Ptr y = std::make_unique<Derived2>();
Base::serialize("x.bin", x);
system("xxd x.bin");
auto x2 = Base::deserialize("x.bin");
Base::serialize("y.bin", y);
system("xxd y.bin");
auto y2 = Base::deserialize("y.bin");
}
一些class有相同的变量,它们都需要序列化,所以我想定义一个抽象class,它有两个纯虚函数serialize()
和deserialize()
以便这些 classes 可以继承它并覆盖功能。
但是我发现重写的函数都是重复的代码,像下面这样:
void Derived::serialize() {
...
ofstream ofs(file, ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << (*this);
}
void Derived::deserialize() {
...
ifstream ifs(file, ios::binary);
boost::archive::bianry_iarchive ia(ifs);
ia >> (*this);
}
我该如何解决这个问题?
我观察到您将 *this
序列化为 Base&
。因为那不是指针类型,所以您无法反序列化派生类型。这让我怀疑你真正拥有什么样的 class 层次结构。
我展示完整的例子:
- 非虚拟层次结构
- 虚拟层次结构/多态序列化
1。非虚拟层次结构
您可以使用 CRTP 来做一些 取决于派生类型的事情:
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/array.hpp>
#include <fstream>
template <typename Derived> class Base {
public:
void serialize() const
{
//...
std::ofstream ofs(file, std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << as_derived();
}
void deserialize() {
//...
std::ifstream ifs(file, std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
ia >> as_derived();
}
protected:
std::string file = "base.bin";
private:
int base_data = 42;
Derived& as_derived() { return static_cast<Derived&>(*this); } ;
Derived const& as_derived() const { return static_cast<Derived&>(*this); } ;
friend class boost::serialization::access;
template <typename Ar> void serialize(Ar& ar, unsigned)
{
ar
& base_data
& as_derived().common_derived_data
;
}
};
struct Derived1 : Base<Derived1> {
private:
friend class Base;
std::array<float, 30> common_derived_data = {1,1,1,1};
};
struct Derived2 : Base<Derived2> {
private:
friend class Base;
std::array<float, 30> common_derived_data = {2,2,2,2};
};
int main() {
Derived1 x;
Derived2 y;
x.serialize();
system("xxd base.bin");
x.deserialize();
y.serialize();
system("xxd base.bin");
x.deserialize();
}
注:
这不再是虚拟层次结构。多态类型 impose constraints on Boost Serialization。你会想要坚持使用 Boost 方法。也许使用简单的免费函数模板来帮助解决重复代码?
2。虚拟层次结构/多态序列化
示例:
注:
- 序列化必须通过指针
- 序列化必须通过指向 Base 的指针(或者至少与序列化的类型相同,所以 a base class 是唯一有意义的)
- 类型必须注册(或假定为抽象),参见 BOOST_CLASS_EXPORT 等
repeated_serialization_code
函数模板现在是重复序列化代码的所在地。- 请注意,必须包括
base_object
This
根据调用上下文推导出const/non-const
#include <boost/archive/binary_oarchive.hpp>
#include <boost/archive/binary_iarchive.hpp>
#include <boost/serialization/serialization.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/unique_ptr.hpp>
#include <boost/serialization/array.hpp>
#include <boost/serialization/export.hpp>
#include <fstream>
class Base {
public:
using Ptr = std::unique_ptr<Base>;
virtual ~Base() = default;
static void serialize(std::string file, Ptr const& ptr)
{
//...
std::ofstream ofs(file, std::ios::binary);
boost::archive::binary_oarchive oa(ofs);
oa << ptr;
}
static Ptr deserialize(std::string file) {
Ptr ptr;
//...
std::ifstream ifs(file, std::ios::binary);
boost::archive::binary_iarchive ia(ifs);
ia >> ptr;
return ptr;
}
protected:
int base_data = 42;
friend class boost::serialization::access;
template <typename Ar> void serialize(Ar& ar, unsigned) { ar& base_data; }
template <typename Ar, typename This>
static inline void repeated_serialization_code(Ar& ar, This& self, unsigned)
{
ar & boost::serialization::base_object<Base>(self)
& self.common_derived_data;
}
};
struct Derived1 : Base {
private:
friend class Mixin;
std::array<float, 30> common_derived_data = {1,1,1,1};
friend class boost::serialization::access;
friend class Base;
template <typename Ar> void serialize(Ar& ar, unsigned v) {
repeated_serialization_code(ar, *this, v);
}
};
struct Derived2 : Base {
private:
friend class Mixin;
std::array<float, 30> common_derived_data = {2,2,2,2};
friend class boost::serialization::access;
friend class Base;
template <typename Ar> void serialize(Ar& ar, unsigned v) {
repeated_serialization_code(ar, *this, v);
}
};
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Base)
BOOST_CLASS_EXPORT(Derived1)
BOOST_CLASS_EXPORT(Derived2)
int main() {
Base::Ptr x = std::make_unique<Derived1>();
Base::Ptr y = std::make_unique<Derived2>();
Base::serialize("x.bin", x);
system("xxd x.bin");
auto x2 = Base::deserialize("x.bin");
Base::serialize("y.bin", y);
system("xxd y.bin");
auto y2 = Base::deserialize("y.bin");
}