У меня есть эти 2 файла, но интерфейс (и компилятор) дают мне эту ошибку, можете ли вы помочь мне найти, что не так? Это действительно странно ... я должен определить все тело моих методов в .cppfile?
//GameMatch.h
#pragma once
#include "Player.h"
namespace Core
{
class GameMatch
{
private:
const static unsigned int MAX_PLAYERS=20;
unsigned int m_HumanControlled;
Score* m_LastDeclaredScore;
Score* m_LastScore;
unsigned int m_MaxPlayers;
Player* m_Players[MAX_PLAYERS];
unsigned int m_PlayerTurn;
inline void NextTurn() { m_PlayerTurn=(m_PlayerTurn+1U)%m_MaxPlayers; }
public:
GameMatch(void);
~GameMatch(void);
void RemovePlayer(Player* _player);
inline Player* getPlayingPlayer() { return m_Players[m_PlayerTurn]; }
};
}
и
//Player.h
#pragma once
#include "IController.h"
#include "GameMatch.h"
#include <string>
#include <Windows.h>
using namespace Core::Controller;
using namespace std;
namespace Core
{
class Player
{
private:
IController* m_Controller;
unsigned int m_Lives;
GameMatch* m_GameMatch;
string m_Name;
bool m_TurnDone;
public:
inline void Die()
{
m_Lives-=1U;
if (m_Lives<1) m_GameMatch->RemovePlayer(this);//m_GameMatch is the first error
}
inline const string& getName() { return m_Name; }
inline bool IsPlayerTurn() { return (m_GameMatch->getPlayingPlayer()==this); }//m_GameMatch is the second error
virtual void Play()=0;
inline Player(GameMatch* _gameMatch,const char* name,unsigned int lives=3)
{
m_GameMatch=_gameMatch;
m_Name=name;
m_Lives=lives;
}
inline void WaitTurn() { while(!IsPlayerTurn()) Sleep(1); }
virtual ~Player()
{
delete m_Controller;
}
};
}
Но, как вы можете видеть, m_GameMatch является указателем, поэтому я не понимаю, почему эта ошибка, возможно, для«рекурсивное включение» заголовочных файлов ...
ОБНОВЛЕНИЕ 1:
//GameMatch.h
#pragma once
#include "Score.h"
#include "Player.h"
namespace Core
{
class GameMatch
{
private:
const static unsigned int MAX_PLAYERS=20;
unsigned int m_HumanControlled;
Score* m_LastDeclaredScore;
Score* m_LastScore;
unsigned int m_MaxPlayers;
Player* m_Players[MAX_PLAYERS];
unsigned int m_PlayerTurn;
inline void NextTurn();
public:
GameMatch(void);
~GameMatch(void);
void RemovePlayer(Player* _player);
inline Player* getPlayingPlayer();
};
}
и
//Player.h
#pragma once
#include "IController.h"
#include "GameMatch.h"
#include <string>
#include <Windows.h>
using namespace Core::Controller;
using namespace std;
namespace Core
{
class Player
{
private:
IController* m_Controller;
unsigned int m_Lives;
GameMatch* m_GameMatch;
string m_Name;
bool m_TurnDone;
public:
inline void Die();
inline const string& getName();
inline bool IsPlayerTurn();
virtual void Play()=0;
inline Player(GameMatch* _gameMatch,const char* name,unsigned int lives=3);
inline void WaitTurn();
virtual ~Player();
};
}
Теперь эти 2 заголовка, однако это все еще не работает, если я не включу Player.h и не буду объявлять класс таким образом в GameMatch.h: class Player;Это работает, однако, что, если я хочу использовать некоторые методы Player? Я должен повторно объявить все ... разве не для этого созданы заголовочные файлы?Я могу включить заголовочный файл во многих местах ... почему я не могу сделать это в этом случае?
РЕШЕНИЕ: Ответ от Alf P. Steinbach в чате: да, и полученный ответ кажется правильным.зависимость циклического заголовка является проблемой.могут быть и другие проблемы, но циклическая зависимость является большой.вам не нужно полное определение класса, чтобы использовать T *.таким образом, обычное прерывание цикла - просто объявить класс вперед, например
class Player;
, который сообщает компилятору, что Player является классом, так что вы можете использовать Player * и Player &, и даже объявлять функции-членыкоторый возвращает Player (хотя вы не можете определить такую функцию, пока класс Player не будет полностью определен), а также конкретный пример, все, что нужно для определения класса Core :: GameMatch, - это предварительное объявление класса Player.затем в файле реализации вы можете включить «player.h».если это необходимо для реализации GameMatch.если вы нарисуете файлы в виде маленьких прямоугольников и нарисуете стрелки, чтобы показать, что они включают в себя, то вы увидите, что это избавляет от циклической зависимостипоэтому я отмечу OJ