«Выражение должно иметь указатель класса» Visual Studio C ++ ошибка - PullRequest
0 голосов
/ 28 ноября 2010

У меня есть эти 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

1 Ответ

1 голос
/ 28 ноября 2010

Вы должны определенно избегать циклического заголовка include.

Разбейте содержимое ваших функций на файлы .cpp вместо того, чтобы помещать все в заголовочные файлы. Кроме того, вместо #include вещей каждый раз, просто объявите вперед.

Если вы удалите циклическое включение, ваш код, скорее всего, будет работать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...