Хранение типа класса в файле

0

У меня есть класс NodeManager. Он в основном сохраняет список Node* и их соединений друг с другом. На самом деле узлами, которыми он управляет, являются классы, полученные из класса Node. Теперь я хочу, чтобы этот NodeManager мог сохранять и все его узлы NodeManager и загружать обратно.

Проблема, с которой я сталкиваюсь, заключается в том, как я могу хранить то, что является производным типом узлов.

Я думал, что - то вроде хранения typeid производного класса и ведения списка возможных типов Node могут быть получены, но я понятия не имею, как я мог бы добиться этого.

Производительность не является проблемой, в любом случае речь идет о <100 узлов. Ответ должен работать мультиплатформенный на windows, linux и mac os. Я хочу, чтобы ответ добавил больше типов узлов тривиально, если это возможно, без изменения кода NodeManager.

Теги:
design

1 ответ

2
Лучший ответ

В базовом классе создайте абстрактный виртуальный метод, который возвращает какой-то "идентификатор". (строка, int, перечисление, что угодно).

В методе "Сохранить" сначала напишите идентификатор для всех классов. Вы можете внедрить запись ID в базовый класс, поэтому производные классы не будут переопределять это поведение.

typedef SomeType ClassId;

class Serializeable{
protected:
   virtual ClassId getClassId() const = 0;
   virtual void saveData(OutStream &out) = 0;
public:
   void save(OutStream &out){
       out << getClassId();
       saveData(out);
   }
};

Создайте фабрику, которая строит требуемый класс с учетом его идентификатора.

--редактировать--

Пример с фабрикой (стандарт С++ 03):

#include <map>
#include <string>
#include <iostream>
#include <QSharedPointer>
#include <utility>

typedef std::string ClassId;
typedef std::ostream OutStream;

class Serializeable{
protected:
    virtual void saveData(OutStream &out) = 0;
public:
    virtual ClassId getClassId() const = 0;
    void save(OutStream &out){
        out << getClassId();
        saveData(out);
    }
    virtual ~Serializeable(){
    }
};

class Derived: public Serializeable{
protected:
    virtual void saveData(OutStream &out){
        out << "test";
    }
public:
    virtual ClassId getClassId() const{
        return "Derived";
    }
};

typedef QSharedPointer<Serializeable> SerializeablePtr; //basically std::shared_ptr

SerializeablePtr makeDerived(){
    return SerializeablePtr(new Derived());
}

class ClassFactory{
protected:
    typedef SerializeablePtr (*BuilderCallback)();
    typedef std::map<ClassId, BuilderCallback> BuilderMap;
    BuilderMap builderMap;

    template<class C> static SerializeablePtr defaultBuilderFunction(){
        return SerializeablePtr(new C());  
    }

public:
    SerializeablePtr buildClass(ClassId classId){
        BuilderMap::iterator found = builderMap.find(classId);
        if (found == builderMap.end())
            return SerializeablePtr();//or throw exception

        return (*(found->second))();
    }

    void registerClass(ClassId classId, BuilderCallback callback){
        builderMap[classId] = callback;
    }
    template<typename T> void registerClassByValue(const T &val){
        registerClass(val.getClassId(), ClassFactory::defaultBuilderFunction<T>);
    }
    template<typename T> void registerClassWithTemplate(ClassId classId){
        registerClass(classId, ClassFactory::defaultBuilderFunction<T>);
    }
};


int main(int argc, char** argv){
    ClassFactory factory;

    std::string derivedId("Derived");
    factory.registerClass(derivedId, makeDerived);
    SerializeablePtr created = factory.buildClass(derivedId);
    created->save(std::cout);
    std::cout << std::endl;

    Derived tmp;
    factory.registerClassByValue(tmp);
    created = factory.buildClass(derivedId);
    created->save(std::cout);
    std::cout << std::endl;

    factory.registerClassWithTemplate<Derived>(derivedId);
    created = factory.buildClass(derivedId);
    created->save(std::cout);
    std::cout << std::endl;
    return 0;
}

QSharedPointer - класс интеллектуальных указателей из Qt 4, что примерно эквивалентно std::shared_ptr. Используйте либо std::shared_ptr либо boost::shared_ptr вместо QSharedPointer в вашем коде.

  • 0
    Я хотел бы видеть реализацию фабрики, где я могу добавлять типы динамически, как Factory.AddType( int, "int"); , Если вы можете это предоставить, я приму этот ответ как более простой, чем использование boost.
  • 0
    @akaltar: добавлен заводской пример.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню