Проблемы с круговой зависимостью
Пытаясь сделать простую игру, я столкнулся с проблемой циклической зависимости. Я искал в интернете и обнаружил, что объявление о форварде может исправить это, но... Оба моих класса зависят от статического значения.
Есть ли какой-нибудь простой способ исправить, например, объявить статические значения вперед или мне нужно переписать ядро моей игры?
2-е РЕДАКТИРОВАНИЕ: Похоже, я был неправ, ошибка все еще там, даже после удаления почти все:
main.cpp:
#include "App.h"
//Start the app
int main(int argc, char* args[]){
App App;
return App.on_execute();
}
App.h:
#ifndef APP_H
#define APP_H
#include "Object.h"
class App
{
public:
//Runs when the program starts
int on_execute();
};
#endif // APP_H
App.cpp:
#include "App.h"
int App::on_execute(){
return 0;
}
Object.h:
#ifndef OBJECT_H
#define OBJECT_H
#include <string>
#include <vector>
#include <stdio.h>
#include <SDL.h>
#include <math.h>
#include "Entity.h"
class Object
{
public:
Object(int character, int x, int y, std::string name, SDL_Color color, bool blocks);
//Object vector
static std::vector<Object*> objects;
};
#endif // OBJECT_H
Object.cpp:
#include "Object.h"
std::vector<Object*> Object::objects;
Object::Object(int character, int x, int y, std::string name, SDL_Color color, bool blocks){
}
Entity.h:
#ifndef ENTITY_H
#define ENTITY_H
#include "Object.h"
#include <sdl.h>
class Entity : public Object
{
public:
Entity(int character, int x, int y, std::string name, SDL_Color color, bool blocks, int hp, int power, int defense);
};
#endif // ENTITY_H
Entity.cpp:
#include "Entity.h"
Entity::Entity(int character, int x, int y, std::string name, SDL_Color color, bool blocks, int hp, int power, int defense) : Object(character, x, y, name, color, blocks){
}
1 ответ
Я думаю, что дизайн вашего кода может быть переработан.
Прежде всего, я бы по-настоящему отговорил вас от использования примитивной, нетривиальной статики классов, где это возможно, будь то классическая статика или глобальная статика. Нетривиальные статические классы будут иметь явный вызов конструктора перед main и должны будут зарегистрировать уничтожение, которое будет вызвано после main. Относительный порядок этих вещей не определен. Хуже того, если позже у вас будет структура библиотеки, такая, что сборка из одного и того же файла.cpp обнаружится дважды, могут произойти странные вещи, когда создаются две копии объекта, но одна и та же уничтожается дважды.
Во-вторых, некоторая информация неясна. Например, вы утверждаете, что класс Map имеет статический член типа Map. Я действительно не думаю, что это возможно; статический член Map также будет иметь объект типа map и т. д. Аналогично с вектором объектов, объявленных внутри объекта. Может быть, в обоих этих случаях вы имеете в виду файл Map.cpp или Object.cpp, а не буквально внутри класса?
В-третьих, уясните, что дает вам предварительная декларация. Это заставляет компиляцию осознавать, что что-то существует, не более того. Это позволяет вам иметь указатели и ссылки на этот тип. Вы не можете создать объект или даже объявить переменную-член типа, объявленного вперед, потому что компилятор не знает размер объекта, объявленного вперед. Вы не можете использовать его методы, потому что компилятор не знает, что они существуют.
В-четвертых, вы вообще не говорили о ваших заголовочных файлах. Это только циклическая зависимость, если Map.h требует Object.h, и наоборот. Два заголовочных файла не могут оба включать друг друга. С другой стороны, реализация находится в Map.cpp и Object.cpp, оба эти файла могут включать и Map.h, и Object.h. Однако лично я предпочитаю избегать взаимозависимых классов.
Вероятно, я бы посоветовал карте владеть объектами, присутствующими на этой карте. Модель с доступом к этому глобальному файлу сейчас не очень хорошая. Вместо того, чтобы объекты были глобальными, сделайте объекты std::vector членами класса Map. Обратите внимание, что если вы решите иметь несколько карт позже, это будет работать намного лучше, каждая карта будет иметь объекты, расположенные на этой карте. Текущий дизайн не работает хорошо, если есть более одной карты.
Затем вы можете реализовать move_to как метод не Object, а скорее Map. Map::move_to(i, dx, dy) перемещает i-й объект.