Создать экземпляр класса на основе строкового ввода

0

Задний план:

В моем игровом движке у меня есть общий "анализатор скриптов", который используется для создания игровых объектов путем анализа файла сценария. Таким образом, в коде у вас будет что-то вроде 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

Есть ли способ сохранить тип класса или что-то в массиве/карте, поэтому, возможно, у меня могла бы быть функция для регистрации списка типов классов со строками, чтобы обеспечить поиск для создания новых экземпляров?

Немного длинный выстрел и может быть невозможен, поэтому, если у кого есть другие предложения о том, как подойти к разбору, они будут приветствоваться

Теги:
sdl
sdl-2

2 ответа

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

Вы можете сохранить тип класса в массиве/карте через 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);
}
  • 0
    Привет, спасибо за информативный ответ. Я попробую и посмотрю, как все пойдет.
  • 0
    Хорошо, мне нравится этот подход, так как он означает, что я могу сделать полный читатель скриптов немного более общим и даже добавить внутренние скриптовые скрипты по мере добавления новых в движок игры. Я попытался осуществить и столкнулся с одной проблемой все же. Это с CMyCustomClass::GetClass() . Если я пытаюсь передать его в соответствии с вашим примером, компилятор завершается с ошибкой «Невозможно инициализировать параметр типа« CBaseClass ( ) () »с lvalue типа« CFont * () »: другой тип возврата (« CBaseClass * «vs») CFont * ') "
Показать ещё 1 комментарий
0

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

Что-то вроде этого:

void RegisterType( std::string name, std::function< BaseType() > createFunc );

При регистрации нового типа вы делаете это так:

RegisterType( "Vehicle", [](){ return new CVehicle; } );

Таким образом, парсер может создавать все производные типы.

Ещё вопросы

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