如何在C ++中实现序列化 [英] How to implement serialization in C++

查看:146
本文介绍了如何在C ++中实现序列化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

每当我发现自己需要在C ++程序中序列化对象时,我会回到这种模式:

 可序列化{
public:
static Serializable * deserialize(istream& is){
int id;
是>> ID;
switch(id){
case EXAMPLE_ID:
return new ExampleClass(is);
// ...
}
}

void serialize(ostream& os){
os< getClassID();
serializeMe(os);
}

protected:
int getClassID()= 0;
void serializeMe(ostream& os)= 0;
};

上面的工作在实践中很好。但是,我听说这种类型的切换ID是邪恶和反模式;什么是标准的OO方式在C ++中处理序列化?

解决方案

使用 Boost序列化虽然绝不是一个标准,但却是(大部分)非常



最后一次我不得不使用清除继承树手动解析预定义的记录结构,我最终使用了< a href =http://en.wikipedia.org/wiki/Factory%5Fpattern>工厂模式与可注册类(即使用键映射到(模板)创建者函数而不是很多开关

编辑

对象工厂的基本C ++实现

  / ** 
*创建对象的类,创建对象的类型基于键
*
* @param K键
* @param所有创建的类派生自的所有类超级类
* /
template< typename K ,类型名称T>
class Factory {
private:
typedef T *(* CreateObjectFunc)();

/ **
*一个映射键(K)到函数(CreateObjectFunc)
*当创建一个新类型时,我们简单地调用所需的键
* /
std :: map< K,CreateObjectFunc> mObjectCreator;

/ **
*此函数的指针插入到映射中,并在创建对象时调用
*
* @param要创建的类的类型
* @返回S类型的对象
* /
template< typename S>
static T * createObject(){
return new S();
}
public:

/ **
*注册一个类,它可以通过createObject()创建
*
* @param S要注册的类,这必须是T
的子类。@param id与类关联的id。此ID必须是唯一的
* /
template< typename S>
void registerClass(K id){
if(mObjectCreator.find(id)!= mObjectCreator.end()){
//你的错误处理在这里
}
mObjectCreator.insert(std :: make_pair< K,CreateObjectFunc>(id,& createObject< S&
}

/ **
*如果给定键存在则返回true
*
* @param id要检查的id存在
* @return true如果id存在
* /
bool hasClass(K id){
return mObjectCreator.find(id)!= mObjectCreator.end();
}

/ **
*基于id创建对象。如果键不存在,它将返回null
*
* @param id要创建的对象的ID
* @返回新对象或null如果对象id不存在存在
* /
T * createObject(K id){
//此处不使用hasClass这样做将涉及两个查找
typename std :: map< K, CreateObjectFunc> :: iterator iter = mObjectCreator.find(id);
if(iter == mObjectCreator.end()){
return NULL;
}
//调用所需的createObject()函数
return((* iter).second)();
}
};


Whenever I find myself needing to serialize objects in a C++ program, I fall back to this kind of pattern:

class Serializable {
  public:
    static Serializable *deserialize(istream &is) {
        int id;
        is >> id;
        switch(id) {
          case EXAMPLE_ID:
            return new ExampleClass(is);
          //...
        }
    }

    void serialize(ostream &os) {
        os << getClassID();
        serializeMe(os);
    }

  protected:
    int getClassID()=0;
    void serializeMe(ostream &os)=0;
};

The above works pretty well in practice. However, I've heard that this kind of switching over class IDs is evil and an antipattern; what's the standard, OO-way of handling serialization in C++?

解决方案

Using something like Boost Serialization, while by no means a standard, is a (for the most part) very well written library that does the grunt work for you.

The last time I had to manually parse a predefined record structure with a clear inheritance tree, I ended up using the factory pattern with registrable classes (i.e. Using a map of key to a (template) creator function rather than a lot of switch functions) to try and avoid the issue you were having.

EDIT
A basic C++ implementation of a object factory mentioned in the above paragraph.

/**
* A class for creating objects, with the type of object created based on a key
* 
* @param K the key
* @param T the super class that all created classes derive from
*/
template<typename K, typename T>
class Factory { 
private: 
    typedef T *(*CreateObjectFunc)();

    /**
    * A map keys (K) to functions (CreateObjectFunc)
    * When creating a new type, we simply call the function with the required key
    */
    std::map<K, CreateObjectFunc> mObjectCreator;

    /**
    * Pointers to this function are inserted into the map and called when creating objects
    *
    * @param S the type of class to create
    * @return a object with the type of S
    */
    template<typename S> 
    static T* createObject(){ 
        return new S(); 
    }
public:

    /**
    * Registers a class to that it can be created via createObject()
    *
    * @param S the class to register, this must ve a subclass of T
    * @param id the id to associate with the class. This ID must be unique
    */ 
    template<typename S> 
    void registerClass(K id){ 
        if (mObjectCreator.find(id) != mObjectCreator.end()){ 
            //your error handling here
        }
        mObjectCreator.insert( std::make_pair<K,CreateObjectFunc>(id, &createObject<S> ) ); 
    }

    /**
    * Returns true if a given key exists
    *
    * @param id the id to check exists
    * @return true if the id exists
    */
    bool hasClass(K id){
        return mObjectCreator.find(id) != mObjectCreator.end();
    } 

    /**
    * Creates an object based on an id. It will return null if the key doesn't exist
    *
    * @param id the id of the object to create
    * @return the new object or null if the object id doesn't exist
    */
    T* createObject(K id){
        //Don't use hasClass here as doing so would involve two lookups
        typename std::map<K, CreateObjectFunc>::iterator iter = mObjectCreator.find(id); 
        if (iter == mObjectCreator.end()){ 
            return NULL;
        }
        //calls the required createObject() function
        return ((*iter).second)();
    }
};

这篇关于如何在C ++中实现序列化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆