首页 > 解决方案 > C++ Cereal:如何在不知道其 polymorphic_id 的情况下加载多态类?

问题描述

我想执行名称和参数存储在 XML 文件中的 c++ 函数列表。因此,我将所有函数都放在派生类中,这样一旦设置了对象,我就可以run关联函数。因此,现在的问题是将我的 XML 文件反序列化为基类的多态指针。

这是能够将 XML 类反序列化为多态指针的Cereal 库(我很幸运)。为此,该库需要 XML 文件中的额外关键字。所以,我必须对我的 XML 文件进行后处理以使其兼容。这不是我喜欢或想要的东西,但好吧,让我们去做吧。

不幸的是,这里开始我的问题。需要的额外关键字之一Cereal是一个名为 的变量polymorphic_id,我事先并不知道这个变量(或者可能会随着时间而改变)。更准确地说,这是一个由(可能通过子例程)polymorphic_id生成的内部变量,所以我寻找一种方法来访问这些内部变量,以便在我的函数名称和它们的. 或解决此预处理步骤的另一种方法。CerealCEREAL_REGISTER_TYPEpolymorphic_id

这是改编自Cereal 文档的 MWE :

#include <string.h>
#include <stdio.h>
#include <iostream>
#include <fstream>
#include <vector>

#include <cereal/archives/xml.hpp>
#include <cereal/types/vector.hpp>
#include <cereal/types/polymorphic.hpp>

using namespace std;
    
class SuperParentClass
{
    private:
        /* data */
    public:
        virtual std::string get_nameClass() =0;
        virtual int run() = 0;
        void serialize() ;
};

class ClassRectangle : public SuperParentClass
{
    private:
        /* data */
    public:
        std::string get_nameClass(){return "Rectangle";};
        double length=0.;
        double width=0.;
        vector<double> center={0., 2.};
        
        template <class Archive>
        void serialize( Archive & ar )
        {
            ar(  CEREAL_NVP( length )  );
            ar(  CEREAL_NVP( width )  );
            ar(  CEREAL_NVP( center )  );
        }

        int run()
        {
            std::cout << "I am a Rectangle with length "<<length << std::endl;
            return 0;
        }
};
CEREAL_REGISTER_TYPE(ClassRectangle);
CEREAL_REGISTER_POLYMORPHIC_RELATION(SuperParentClass, ClassRectangle)

class ClassCircle : public ClassRectangle
{
    private:
        /* data */
    public:
        std::string get_nameClass(){return "Circle";};
        double radius=0.;
        vector<double> center={0., 2.};
        
        template <class Archive>
        void serialize( Archive & ar )
        {
            ar(  CEREAL_NVP( radius )  );
            ar(  CEREAL_NVP( center )  );
        }

        int run()
        {
            std::cout << "I am a Cricle with radius "<<radius << std::endl;
            return 0;
        }
};
CEREAL_REGISTER_TYPE(ClassCircle);
CEREAL_REGISTER_POLYMORPHIC_RELATION(ClassRectangle, ClassCircle)


int main(void) 
{ 
    // Beginning of main.
    cout << "(Start)" << endl;
    
    // Save Part.
    { 
        cout << "SAve " << endl; 
        std::shared_ptr<SuperParentClass> Shape = std::make_shared<ClassRectangle>();
        std::ofstream outs("Input_1.xml");
        cereal::XMLOutputArchive archive( std::cout ); //( outs ) ;// ( std::cout ); //
        archive( cereal::make_nvp(Shape->get_nameClass(), Shape) );
        Shape = std::make_shared<ClassCircle>();
        archive( cereal::make_nvp(Shape->get_nameClass(), Shape) );
    }

    // Load Part.
    cout << "Load " << endl; 
    std::ifstream is("Input_2.xml"); // NEEDS TO BE REPLACE BY "Input1.xml" 
    cereal::XMLInputArchive arr(is); 
    std::shared_ptr<SuperParentClass> ShapeBis;
    arr( cereal::make_nvp("Rectangle", ShapeBis) );
    ShapeBis->run();
    arr( ShapeBis );
    ShapeBis->run();

    // End of the main.
    cout << "(End) " << endl;   
    return 0; 
} 
// EoF

在这个 MWE 中,该文件Input_2.xml是我拥有的 XML 文件,我应该后处理:

<?xml version="1.0"?>
<Rectangle>
    <length>2.3</length>
    <width>0</width>
    <center size="dynamic">
        <value0>0</value0>
        <value1>1</value1>
    </center>
</Rectangle>
<Circle>
    <radius>10.</radius>
    <center size="dynamic">
        <value0>1</value0>
        <value1>1</value1>
    </center>
</Circle>

而文件Input_1.xml是序列化的结果,是我在Input_2.xml.

Input_1.xml

<?xml version="1.0" encoding="utf-8"?>
<cereal>
    <Rectangle>
        <polymorphic_id>2147483649</polymorphic_id>
        <polymorphic_name>ClassRectangle</polymorphic_name>
        <ptr_wrapper>
            <id>2147483649</id>
            <data>
                <length>22.3</length>
                <width>0</width>
                <center size="dynamic">
                    <value0>0</value0>
                    <value1>2</value1>
                </center>
            </data>
        </ptr_wrapper>
    </Rectangle>
    <Circle>
        <polymorphic_id>2147483660</polymorphic_id>
        <polymorphic_name>ClassCircle</polymorphic_name>
        <ptr_wrapper>
            <id>2147483660</id>
            <data>
                <radius>10.</radius>
                <center size="dynamic">
                    <value0>1</value0>
                    <value1>1</value1>
                </center>
            </data>
        </ptr_wrapper>
    </Circle>
</cereal>

那么如何在不知道其 polymorphic_id 的情况下使用 Cereal 加载多态类呢?或者换句话说,如何在内部 polymorphic_id 和我的类名之间创建映射?

标签: c++hashpolymorphismcereal

解决方案


推荐阅读