Задний план:
В моем игровом движке у меня есть общий "анализатор скриптов", который используется для создания игровых объектов путем анализа файла сценария. Таким образом, в коде у вас будет что-то вроде MyEntity* entity = MyScriptParer::Parse("filename.scr");
Любой класс, который должен быть scriptable, наследуется от базового базового класса. Внутри игрового движка есть некоторые конкретные классы, которые используют это: частицы, шрифты и т.д., И все это прекрасно работает в синтаксическом анализаторе.
std::string line;
std::getline(ifs, line);
if (line == "[FONT]") {
CFont* f = new CFont();
f->readObject(ifs);
}
else if (line == "[PARTICLE]") {
CParticle* p = new CParticle();
p->readObject(ifs);
}
...
Моя проблема связана с тем, как обрабатывать определенные пользователем классы, т.е. классы в играх, в которых используется движок игры. Базовый класс имеет абстрактный метод readObject
поэтому все, что наследует, должно реализовать этот метод.
Проблема в том, как парсер узнает о новом классе? Например, скажем, что у меня есть класс CVehicle
который теперь должен знать парсер, чтобы распознать "[АВТОМОБИЛЬ]", а также иметь возможность создать new CVehicle
Есть ли способ сохранить тип класса или что-то в массиве/карте, поэтому, возможно, у меня могла бы быть функция для регистрации списка типов классов со строками, чтобы обеспечить поиск для создания новых экземпляров?
Немного длинный выстрел и может быть невозможен, поэтому, если у кого есть другие предложения о том, как подойти к разбору, они будут приветствоваться
Вы можете сохранить тип класса в массиве/карте через std :: type_info
Однако вы не можете создать тип из этого, поскольку для этого потребуется больше RTTI, чем доступно в C++. (например, отражение в.NET).
Тем не менее, вы можете сохранить указатель функции на фабрику классов на такой карте. Т.е.
typedef CBaseClass* (*pfnCreateClass)();
std::map<std::string, pfnCreateClass> mapCreate;
// Registering
// CMyCustomClass::GetClass() is a static method that creates a CMyCustomClass
mapCreate.insert(std::pair<std::string, pfnCreateClass>("[CUSTOM_CLASS]", CMyCustomClass::GetClass));
// Get class
std::map<std::string, pfnCreateClass>::const_iterator it = mapCreate.find(line);
if(mapCreate.end() != it)
{
CBaseClass *p = it->second();
p->readObject(ifs);
}
Просто имейте функцию, чтобы зарегистрировать новый тип take в имени типа и функции для создания типа.
Что-то вроде этого:
void RegisterType( std::string name, std::function< BaseType() > createFunc );
При регистрации нового типа вы делаете это так:
RegisterType( "Vehicle", [](){ return new CVehicle; } );
Таким образом, парсер может создавать все производные типы.
CMyCustomClass::GetClass()
. Если я пытаюсь передать его в соответствии с вашим примером, компилятор завершается с ошибкой «Невозможно инициализировать параметр типа« CBaseClass ( ) () »с lvalue типа« CFont * () »: другой тип возврата (« CBaseClass * «vs») CFont * ') "