У меня есть класс NodeManager
. Он в основном сохраняет список Node*
и их соединений друг с другом. На самом деле узлами, которыми он управляет, являются классы, полученные из класса Node
. Теперь я хочу, чтобы этот NodeManager
мог сохранять и все его узлы NodeManager
и загружать обратно.
Проблема, с которой я сталкиваюсь, заключается в том, как я могу хранить то, что является производным типом узлов.
Я думал, что - то вроде хранения typeid
производного класса и ведения списка возможных типов Node
могут быть получены, но я понятия не имею, как я мог бы добиться этого.
Производительность не является проблемой, в любом случае речь идет о <100 узлов. Ответ должен работать мультиплатформенный на windows, linux и mac os. Я хочу, чтобы ответ добавил больше типов узлов тривиально, если это возможно, без изменения кода NodeManager
.
В базовом классе создайте абстрактный виртуальный метод, который возвращает какой-то "идентификатор". (строка, 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
в вашем коде.
Factory.AddType( int, "int");
, Если вы можете это предоставить, я приму этот ответ как более простой, чем использование boost.