allegro5 — Создание списка, к которому должны обращаться классы, использующие переполнение стека

Мне нужно создать глобальный список, к которому может обращаться и использовать группа классов, которые я инициализировал, но эти классы должны быть включены для создания списка. Есть идеи?

Пример:

class Game_object
{
public:
~Game_object()
void Update();
void Render();
//Other stuff
};

class Explosion
{
Stuff
};

class Player
{
Stuff
};

Все эти классы должны получить доступ к приведенному ниже списку, который находится в другом заголовочном файле, а также мой int main

std::list <Game_object *> Objects;
std::list <Explosion *> Explosions;

И так далее.

Идея состояла в том, чтобы я мог создать экземпляр взрыва в деструкторе объекта Game_object и поместить его в список. Это было так, чтобы я мог иметь его рендеринг и обновление внутри главного

2

Решение

Ты имеешь в виду Game_object должен держать std::list<Explosion *> а также Explosion должен держать std::list<Game_object *>? Это звучит как работа для предварительные декларации:

#include <list>

class Game_object;
class Explosion;

class Game_object
{
std::list<Explosion *> l;
};

class Explosion
{
std::list<Game_object *> l;
};

Это работает, потому что ваши списки содержат указатели, не актуальные объекты.

3

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

Объявите ваши списки в заголовочном файле (например, mylists.h) следующим образом:

#include <list>
#include <myGameClasses.h>

class Game_object;
class Explosion;

extern std::list<Game_object*> Objects;
extern std::list<Explosion*> Explosions;
// And so for other lists

Использование extern создаст ссылочная декларация для ваших списков. Затем вы должны создать определяющие декларации в исходном файле (например, mylists.cpp):

#include "mylists.h"
std::list<Game_object*> Objects;
std::list<Explosion*> Explosions;
// And so for other lists

Почему ты должен делать это так? Это необходимо для предотвращения нескольких объявлений при включении вашего заголовка (mylists.h). Тогда потребуется только одна декларация, которая, в данном случае, в исходном файле (mylists.cpp).

Чтобы иметь возможность использовать списки, просто включите заголовочный файл.

Кроме того, в mylists.h также необходимо предварительные декларации из ваших классов:

class Game_object;
class Explosion;

Это сделано для того, чтобы избежать ошибок необъявленного идентификатора.

0

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

// forward declare Game_object:
class Game_object;

// Declare lists:
typedef std::list <Game_object *> ListObjects;
typedef std::list <Explosion *> ListExplosions;
ListObjects Objects;
ListExplosions Explosions;

class Game_object
{
public:
void Update()
{
// Update Objects...
for (ListObjects::const_iterator O = Objects.begin(); O != Objects.end(); ++O)
{ ... };
// Update Explosions...
for (ListExplosions::const_iterator E = Explosions.begin(); E != Explosions.end(); ++E)
{ ... };
};
void Render()
{
// Render Objects...
for (ListObjects::const_iterator O = Objects.begin(); O != Objects.end(); ++O)
{ ... };
// Render Explosions...
for (ListExplosions::const_iterator E = Explosions.begin(); E != Explosions.end(); ++E)
{ ... };
};
//Other stuff
};

Это не очень хорошая идея, глобальные переменные могут быть проблематичными, а еще хуже — с глобальными списками, к которым могут обращаться другие классы и изменять их содержимое, в то время как другой класс пытается изменить содержимое одновременно; но если вы не используете темы, это может быть не так уж сложно.

Другим подходом может быть создание менеджера. Менеджер должен быть владельцем списка и нуждаться в методах Setters, Getters, а также Deleters методы. Чтобы обновить содержимое списка, вы можете передать ссылку на менеджер в средство визуализации / обновления и получить ссылку на список от менеджера:

class ObjectManager
{
public:
typedef std::list <Game_object *> ListObjects;

void AddObject(const ObjectStuff &os)
{ ... };

const ListObjects &GetObjects()
{ return Objects; };

private:
ListObjects Objects;
}

class ExplosionManager
{
public:
typedef std::list <Explosion *> ListExplosions;

void AddExplosion(const ExplosionStuff &es);
{ ... };

const ListExplosions &GetExplosions()
{ return Explosions; };

private:
ListExplosions Explosions;
}

void Render(const ObjectManager &om)
{
// Ask ObjectManager for the object list
}

void Render(const ExplosionManager &em)
{
// Ask ExplosionManager the explosion list
}

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


Это не спрашивается, но я думаю, что стоит сказать: может быть хорошей идеей избежать хранения указателей объектов в контейнерах и изменить тип хранилища для экземпляров объектов:

std::list <Game_object *> VS std::list <Game_object>

Когда вы используете указатели, вы должны позаботиться о распределении и освобождении объектов, если списки являются глобальными, вам понадобится публичный Close метод для освобождения всей памяти, управляемой указателями, хранящимися в списках, если список принадлежит какому-либо объекту, вам необходимо выполнить тот же процесс в деструкторе объекта.

Но если вы храните экземпляры объектов, деструктор списка освобождает все объекты, хранящиеся по истечении срока его службы, код становится чище и проще в обслуживании.

0
По вопросам рекламы [email protected]