C++ 在没有公共基类的情况下实现序列化
我正在为以下问题寻求一些设计建议: 我使用的是boost geometry,我有几个与boost geometry兼容的自定义几何类型(通过traits),但我使用的大多数类型都是typedefC++ 在没有公共基类的情况下实现序列化,c++,serialization,boost,boost-geometry,C++,Serialization,Boost,Boost Geometry,我正在为以下问题寻求一些设计建议: 我使用的是boost geometry,我有几个与boost geometry兼容的自定义几何类型(通过traits),但我使用的大多数类型都是typedef class MyPoint { // custom stuff }; // declare traits for MyPoint for use wih boost geometry here class MyTaggedPoint : public MyPoint { // more cus
class MyPoint
{
// custom stuff
};
// declare traits for MyPoint for use wih boost geometry here
class MyTaggedPoint : public MyPoint
{
// more custom stuff
};
// declare traits for MyTaggedPoint for use wih boost geometry here
// example typedefs
typedef boost::geometry::model::polygon<MyPoint> Polygon;
typedef boost::geometry::model::polygon<MyTaggedPoint> TaggedPolygon;
类MyPoint
{
//定制物品
};
//在此处声明MyPoint的特性,以便与boost几何体一起使用
类MyTaggedPoint:公共MyPoint
{
//更多定制的东西
};
//声明MyTaggedPoint的特性,以便在此处与boost几何体一起使用
//示例typedefs
typedef boost::geometry::model::polygon;
typedef boost::geometry::model::polygon标记多边形;
我的问题是何时要序列化/反序列化几何图形
假设所有几何图形都存储在数据库的二进制字段中。如果我有一个基本的几何类,我可能只需要编写g->type()(4字节)并调用g->save(some_outputstream)并将所有这些写入二进制字段。然后在读取二进制字段时,我只需读取字节并转换为适当的几何体类型
但是推进几何体没有通用的基类
当有多个类型可以存储为二进制且没有共享基类时,你们通常如何实现序列化?
我在考虑可能有一个序列化程序类,它会返回一个提升。然后可以使用(反)序列化程序中存储的类型对几何体进行强制转换?但是序列化程序需要为每种几何体类型使用一个save方法?例如:保存(myPolygon),保存(myPoint)
有什么想法/经验吗?如果您不希望重新实现控制盘,则支持非侵入式序列化。您甚至可以在某个地方找到对其几何图形类型的库支持。不幸的是,由于XML方面的考虑,接口有点复杂。要将对象序列化到字节和从字节序列化对象,对于必须支持的每种类型(灵长类、对象等),最终需要两个函数。它们是“Load()”和“Store()” 理想情况下,您可以为字节使用一个固定的接口—iostream、char*、一些缓冲区对象—等等。 为了可读性,让我们称之为“ByteBuffer”,因为从逻辑上讲,这就是它的作用 我们现在有一些类似于可序列化概念的模板函数:
template<typename T>
ByteBuffer Store(const T& object) { // BUT, What goes here...? }
template<typename T>
T Load(const ByteBuffer& bytes);
为了检查错误,我们可以在派生构造函数可以设置的基类中提供一个受保护的标志“valid”。请注意,您的对象必须支持工厂样式的构造,Load()才能很好地使用它
现在我们可以这样做了,作为工厂提供“负载”:
template<typename T>
class Serializable // If you do reference-counting on files & such, you can add it here
{
protected:
bool valid;
// Require derived to mark as valid upon load
Serializable() : valid(false) {}
virtual ~Serializable() { valid = false; }
public:
static T Load(const ByteBuffer& bytes); // calls a "T(bytes)" constructor
// Store API
virtual ByteBuffer Store() = 0; // Interface details are up to you.
};
模板
类Serializable//如果您对文件进行引用计数,那么可以将其添加到此处
{
受保护的:
布尔有效;
//要求在加载时将派生标记为有效
Serializable():有效(假){}
virtual~Serializable(){valid=false;}
公众:
静态T加载(constbytebuffer&bytes);//调用“T(bytes)”构造函数
//存储API
virtual ByteBuffer Store()=0;//接口详细信息由您决定。
};
现在,只需像这样从基类派生,就可以获取所需的一切:
class MyObject : public Serializable<MyObject>
{
protected:
// .. some members ...
MyObject(const ByteBuffer& bytes)
{
//... Actual load logic for this object type ...
// On success only:
valid = true;
}
public:
virtual ByteBuffer Store() {
//... store logic
}
};
类MyObject:可公共序列化
{
受保护的:
//……一些成员。。。
MyObject(常量字节缓冲和字节)
{
//…此对象类型的实际加载逻辑。。。
//仅就成功而言:
有效=真;
}
公众:
虚拟ByteBuffer存储(){
//…存储逻辑
}
};
最酷的是,您可以调用“MyObject::Load()”,它将完全按照您的期望执行。此外,“加载”可以成为构建对象的唯一方式,允许您为只读文件等清理API
将其扩展到完整文件API需要更多的工作,即添加一个可以从更大的缓冲区(保存其他内容)读取的“Load()”和附加到现有缓冲区的“Store()”
请注意,不要为此使用boost的API。在一个好的设计中,可序列化对象应该1对1映射到磁盘上原始类型的压缩结构——这是生成的文件真正可供其他程序或其他机器使用的唯一方法。Boost为您提供了一个可怕的API,它主要使您能够做一些您以后会后悔的事情。+1用于Boost.Serialization,尤其是因为他已经在使用Boost。
class MyObject : public Serializable<MyObject>
{
protected:
// .. some members ...
MyObject(const ByteBuffer& bytes)
{
//... Actual load logic for this object type ...
// On success only:
valid = true;
}
public:
virtual ByteBuffer Store() {
//... store logic
}
};