2013-10-06 6 views
0

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

В моем игровом движке у меня есть общий «сценарий парсер», который используется для создания игровых объектов путем анализа файла сценарий. Таким образом, в коде у вас есть что-то вроде MyEntity* entity = MyScriptParer::Parse("filename.scr");

Любой класс, который должен быть доступен для скриптинга, наследуется от базового базового класса. Внутренне в игровом движке есть некоторые конкретные классы, которые используют это - частицы, шрифты и т.д., и все это прекрасно работает в синтаксический анализатор - см экстракт ниже

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

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

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

ответ

1

Вы можете магазин тип класса в массиве/карте через std::type_info

Однако, вы не можете создать тип от этого, так как это потребует больше RTTI, чем доступно в C++. (например, отражение в .NET).

Однако вы можете сохранить указатель на объект класса на такой карте. I.e.

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

привет, спасибо за информативный ответ. Я попробую и посмотрю, как это происходит. – Zammalad

+0

OK Мне нравится этот подход, так как это означает, что я могу сделать полный скрипт-читатель более универсальным и добавить даже внутренние скриптовые расширения, добавив новые движки игры. Однако я попытался реализовать и решить одну проблему. Это с частью 'CMyCustomClass :: GetClass()'. Если я попытаюсь передать его в соответствии с вашим примером, компилятор завершит с ошибкой «Невозможно инициализировать параметр типа« CBaseClass * (*)() »с lvalue типа« CFont *() »: другой тип возврата (« CBaseClass * vs 'CFont *') " – Zammalad

+1

Я исправил свою проблему. Простая ошибка в том, что я передал указатель на новый класс клиента 'CFont' в этом случае вместо того, чтобы передавать его указатель базового класса – Zammalad

0

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

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

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

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

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

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

Смежные вопросы