Класс действий в C ++? (эквивалентно C #)

В моем игровом движке C # я использовал обработку упорядоченного рисования путем добавления / удаления действия к объекту менеджера, который сортировал действия по приоритету, а затем выполнял их.

Вот очень упрощенный пример:

class DrawManager
{
public List<Tuple<Action, int>> DrawActions = new List<Tuple<Action, int>>();
void Draw() { foreach (var tuple in DrawActions) tuple.Item1(); }
}

class Example
{
DrawManager manager;

Example()
{
manager.DrawActions.Add(new Tuple<Action, int>(DrawBackground, 0));
manager.DrawActions.Add(new Tuple<Action, int>(DrawForeground, 100));
}
~Example()
{
manager.DrawActions.Remove(manager.DrawActions.Find(x => x.Item1 == DrawBackground));
manager.DrawActions.Remove(manager.DrawActions.Find(x => x.Item1 == DrawForeground));
}

void DrawBackground() { /* draw something */ }
void DrawForeground() { /* draw something */ }
}

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

Я недавно перешел на C ++, и я не могу найти простой способ достичь того же результата.

Я попытался использовать std :: function, но для того, чтобы удалить метод уничтожения объекта, мне пришлось сохранить метод draw в указателе, принадлежащем вызывающей стороне, затем обернуть его в лямбду и передать его. Очень не элегантно и требует много времени ,

Есть ли способ получить код, аналогичный показанному в примере C #?

1

Решение

Ты можешь использовать std::function на месте Action:

typedef std::function<void()> Action;
std::vector<std::pair<Action, int> > DrawActions;
void Draw() {
for_each(DrawActions.begin(), DrawActions.end(), [](std::pair<Action, int>& a) {
a.first();
});
}
4

Другие решения

Другая идея — не использовать std :: function, а использовать std :: set, и вы создаете класс для каждого действия, которое хотите выполнить. Идея состоит в том, что классы действий определены в файле cpp (а не в заголовочных файлах, если они не являются общими) класса, который их использует, они полностью скрыты.

Сначала определите действие класс, он имеет чисто виртуальный выполнять, уровень приоритета и указатель на какого-то владельца. Идея состоит в том, чтобы не создавать другие классы, кортежи, а использовать действие класс для хранения этих значений:

class Action
{
public:
Action(const int priority, void * owner) : priority(priority), owner(owner) {}
virtual ~Action() {}

virtual void execute() = 0;

struct PrioritySorter
{
bool operator()(Action* a, Action* b)
{
return a->priority < b->priority;
}
};

bool ownerIs(void * owner) const { return this->owner == owner; }

private:
const int priority;
void * owner;
};

Затем создайте несколько действий:

class DrawBackgroundAction : public Action
{
public:
DrawBackgroundAction(const int priority, void * owner) : Action(priority, owner) {}

void execute()
{
cout << "drawing background" << endl;
}
};

class DrawForegroundAction : public Action
{
public:
DrawForegroundAction(const int priority, void * owner) : Action(priority, owner) {}

void execute()
{
cout << "drawing foreground!!!" << endl;
}
};

class DrawSomethingElseAction : public Action
{
public:
DrawSomethingElseAction(const int priority, void * owner) : Action(priority, owner) {}

void execute()
{
cout << "drawing something else" << endl;
}
};

DrawManager заботится о сохранении действий в отсортированном наборе по приоритету, и если вы хотите удалить «собственные» действия (некоторый другой класс), вы можете сделать это.

class DrawManager
{
public:
DrawManager() {}
~DrawManager()
{
for ( ActionList::iterator i = actions.begin(), e = actions.end(); i != e; i++ )
{
delete *i;
}
actions.clear();
}

void draw()
{
for ( ActionList::iterator i = actions.begin(), e = actions.end(); i != e; i++ )
{
(*i)->execute();
}
}

void addAction(Action* action)
{
actions.insert(action);
}

void removeOwnedActions(void * owner)
{
for ( ActionList::iterator i = actions.begin(), e = actions.end(); i != e; i++)
{
if ( (*i)->ownerIs(owner) )
{
delete *i;
actions.erase(i);
}
}
}

private:
typedef std::set<Action*,Action::PrioritySorter> ActionList;
ActionList actions;
};

Теперь пример класса:

class Example
{
public:
Example()
{
manager.addAction(new DrawForegroundAction(100,this));
manager.addAction(new DrawBackgroundAction(0,this));
manager.addAction(new DrawSomethingElseAction(50,this));
}

void drawAll()
{
manager.draw();
}

void removeTheActionsIfYouWant()
{
manager.removeOwnedActions(this);
}

private:
DrawManager manager;
};

И тест:

int main()
{
Example ex;

cout << "Drawing all" << endl;

ex.drawAll();

ex.removeTheActionsIfYouWant();

cout << "Drawing again" << endl;

ex.drawAll();

return 0;
}
0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector