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

时间:2010-05-24 22:21:07

标签: c++ boost

我正在查看boost序列化库,并且为序列化提供支持的侵入式方法是使用签名(简化)定义成员函数:

class ToBeSerialized {
public:
    //Define this to support serialization
    //Notice not virtual function!
    template<class Archive>
    void serialize(Archive & ar)
    {.....}
};

此外,支持派生类槽基指针的血清化的一种方法是使用类型的宏:

//No mention to the base class(es) from which Derived_class inherits
BOOST_CLASS_EXPORT_GUID(Derived_class, "derived_class")

其中Derived_class是一个继承自基类的类,比如Base_class。多亏了这个宏,可以通过指向Base_class的指针正确序列化Derived_class类。

问题是: 我在C ++中用来编写通过从std :: string到(指向)函数的映射实现的抽象工厂,这些函数返回所需类型的对象(并且由于协变类型,eveything很好)。

悬停我没有看到如何使用上面的非虚拟序列化模板成员函数来正确反序列化(即构造)一个对象而不知道它的类型(但假设类型信息已由序列化程序存储,在一个字符串中说。)

我想做的事(保持与上面相同的术语)如下所示:

XmlArchive xmlArchive; //A type or archive
xmlArchive.open("C:/ser.txt"); //Contains type information for the serialized class
Base_class* basePtr = Factory<Base_class>::create("derived_class",xmlArchive);

使用右侧的函数在Derived_class类型的堆上创建一个对象(通过默认构造函数,这是我知道如何解决的部分)并调用xmlArchive的serialize函数(这里我被卡住!) ,即做类似的事情:

Base_class* Factory<Base_class>::create("derived_class",xmlArchive)
{
    Base_class* basePtr = new Base_class; //OK, doable, usual map string to pointer to function
    static_cast<Derived_class*>( basePtr )->serialize( xmlArchive ); //De-serialization, how?????
    return basePtr;
}

我确信这可以完成(boost serialize会这样做,但它的代码是难以穿透的!:P),但我没弄明白怎么做。 关键问题是序列化函数是模板函数。所以我不能指向通用的模板化函数。 由于编写模板化序列化函数的目的是使代码通用(即不必为不同的Archivers重新编写序列化函数),因此必须为所有可能的归档类型注册所有派生类是没有意义的。 ,像:

MY_CLASS_REGISTER(Derived_class, XmlArchive);
MY_CLASS_REGISTER(Derived_class, TxtArchive);
...

事实上,在我的代码中,我依赖重载来获得正确的行为:

void serialize( XmlArchive& archive, Derived_class& derived );
void serialize( TxtArchive& archive, Derived_class& derived );
...

要记住的关键点是归档类型总是已知的,即我永远不会对归档类使用运行时多态性...(我再次使用归档类型的重载)。

有什么建议可以帮助我吗?

非常感谢你!

干杯

2 个答案:

答案 0 :(得分:0)

如果您的存档类型始终是已知的,为什么还要在其上设置serialize函数的参数?对于代码重用有一个争论,是的,但如果你的Archive类改变了它的定义或被替换,你可能还需要重构一些序列化代码。

如果坚持:

class ToBeSerialized : public Base_class {
public:
    void serialize(Archive & ar)
    {.....}
};

然后,您可以指向serialize函数的指针,并将其绑定到您的工厂。

您还需要为每个类绑定单独的create函数,以便在要求它时可以实例化正确的类型。类似的东西:

template <typename T> Base_class* Factory::create(Archive& xmlArchive) {
    T* derivedPtr = new T;
    derivedPtr->serialize( xmlArchive );
    return derivedPtr;
}

然后工厂需要一个通用create方法来调用正确的静态参数化create<T>

Base_class* Factory::create(const char* typeString, Archive& xmlArchive) {
    // Pseudocode.
    return m_map.find(typeString)->callCreate(xmlArchive);
}

答案 1 :(得分:0)

您需要的是在存储来自派生类型的信息之前存储某种标识符。然后在阅读时使用您首先阅读的标识符,将您引导到工厂,然后工厂可以正确解释下一个信息块并生成派生类型。这可能是boost :: serialization在一个非常基础的层面上所做的。也许是这样的:


ar >> type;
Base_class* basePtr = Factory<Base_class>::create(type,xmlArchive);

然后你有一个看起来像这样的对象的地图:

struct reader_base { virtual void load(xmlArchive, base_ptr) = 0; } template < typename T > struct reader : reader_base { virtual void load(xmlArchive, base_ptr) { static_cast<T*>(base_ptr)->serialize(xmlArchive); } };