es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo deserializar clases polimórficas?

Tengo una clase base abstracta llamada User, de la que heredan Student y Professor. User tiene funciones virtuales para escribir en un archivo (serialización) que son sobreescritas en las clases derivadas.

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() << ",";
}

También tiene una función para leer desde un archivo (deserialización). El problema es que, cuando leo typeid(*this).raw_name() desde el archivo, no sé cómo acceder a Student o Professor para poder instanciar uno de ellos. Estoy usando una clase de estructura de datos de plantilla, por lo que no puedo verificar eso explícitamente.

“`cpp
template <typename t="">
class UndirectedGraph {

<pre><code>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) {
// aquí obtengo esa información, pero ¿cómo la uso para declarar el tipo de la clase derivada?
std::getline(ifs, type, ',');
ifs >> obj;
});
}
</code></pre>

}
“`</void(t&)></void(const>

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Para resolver este problema, podrías agregar una función virtual en la clase base Usuario que devuelva un identificador único para cada clase derivada. Por ejemplo:

    virtual std::string obtener_tipo() const = 0;
    

    Luego, en cada clase derivada, puedes implementar esta función para devolver una cadena única, como:

    std::string Estudiante::obtener_tipo() const {
        return "Estudiante";
    }
    
    std::string Profesor::obtener_tipo() const {
        return "Profesor";
    }
    

    Ahora, cuando lees typeid(*this).raw_name() desde un archivo en la función leer de la clase GrafoNoDirigido, puedes compararlo con los identificadores únicos devueltos por la función obtener_tipo() para determinar el tipo de la clase derivada. Por ejemplo:

    virtual void leer(std::ifstream& ifs) override {
        std::string tipo;
        for_each_DFS(0, [&ifs](T& obj) { 
            std::getline(ifs, tipo, ','); 
            if (tipo == "Estudiante") {
                obj = new Estudiante();
            } else if (tipo == "Profesor") {
                obj = new Profesor();
            } else {
                // manejar error
            }
            ifs >> *obj;
        });
    }
    

    De esta manera, puedes asignar dinámicamente objetos del tipo correcto y deserializarlos desde un archivo sin tener que depender de la función typeid.

Comments are closed.