如何反序列化多态类?

3

我有一个抽象的基类 User,被 StudentProfessor 继承。 User 中有用于向文件中写入数据(序列化)的虚函数,派生类对其进行了重写。

void Student::write(std::ofstream& ofs) const {
    ofs << typeid(*this).raw_name() << id << "," << get_name() << "," << get_surname() << ",";
}

void Professor::write(std::ofstream& ofs) const {
    ofs << typeid(*this).raw_name() << title << "," << get_name() << "," << get_surname() << ",";
}

它还具有从文件读取(反序列化)的功能。问题是,当我从文件中读取 typeid(* this).raw_name() 时,我不知道如何访问 StudentProfessor ,以便我可以实例化其中之一。 我正在使用模板数据结构类,所以无法明确检查。
    template <typename T>
    class UndirectedGraph { ...

        void for_each_DFS(int vertex, const std::function<void(const T&)>& func) const {
            for (const auto value : *nodes.at(vertex))
                func(value);
        }

        void for_each_DFS(int vertex, const std::function<void(T&)>& func) {
            for (auto value : *nodes[vertex])
                func(value);
        }

        virtual void write(std::ofstream& ofs) const override {
            if (std::is_pointer<T>::value)
                for_each_DFS(0, [&ofs](const T& obj) { ofs << *obj; });
            else
                for_each_DFS(0, [&ofs](const T& obj) { ofs << obj; });
        }

        virtual void read(std::ifstream& ifs) override {
            std::string type;
            for_each_DFS(0, [&ifs](T& obj) { 
                // here I get that info, but how do I use it do declare type of derived class?
                std::getline(ifs, type, ','); 
                ifs >> obj;
            });
        }
    }

1
我认为你需要一个像这样的工厂函数:std::unique_ptr<User*> create_user(const std::string& type);,实现是一系列的 if,然后 User 实例可以完成其解析。 - MatG
这实际上是一个非常复杂的主题。我会在每个派生类中使用一些静态元数据(名称字符串、创建对象函数和删除对象函数)和一些基类中的静态元数据(指向派生元数据的指针向量)。然后,我将通过搜索基类元数据来查找创建函数。auto name = ReadName(...); auto metadata = Base :: GetMetadata(name); auto * obj = metadata-> createObj(); obj-> read(...); - Osyotr
多态对象很难序列化,因为它们本质上不是值类型。如果您想像值一样处理它们,您必须将它们封装在行为类似于值的类型擦除类中。一旦您完成了这个过程,您就会有一个很好的想法如何序列化它们。请参阅Sean Parent的"Inheritance is the base class of Evil"。话虽如此,Boost.Serialization通过多态指针进行序列化的努力是英勇的。 - alfC
1个回答

0

这里是一种可能的解决方案,使用 std::anystd::type_index

#include <any>
#include <string>
#include <typeinfo>
#include <typeindex>
#include <unordered_map>

class A {};
class B {};

template<typename T>
std::string write(){
    static const std::unordered_map<std::type_index, std::string> kTypeNames{{typeid(A), "A"}, {typeid(B), "B"}};
    return kTypeNames.at(typeid(T));
}

std::any read(const std::string& s){
   if(s == "A") return A{};
   if(s == "B") return B{};
   return {};
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接