Как использовать классы внутри другой функции класса независимо от того, где она объявлена ​​в C ++? - PullRequest
0 голосов
/ 08 января 2019

Я пытаюсь создать игру Monopoly на C ++, и я возился с объектно-ориентированным программированием, проблема возникает с классами "Game" и "Player", я хотел бы знать, как использовать " Функции Game "внутри" Player "и функции" Player "внутри" Game ", но я получаю сообщение об ошибке компилятора о том, что класс не определен.

Переключение позиций класса не сработает (очевидно), но я все равно попробовал.

Код (уменьшен и уменьшен до классов Game и Player):

    namespace Monopoly {
typedef enum { normal, train, company, incometax, luxurytax, start, chancecard, chestcard, jail } type;
class Game {
private:
    bool running = false;
    int turn = 1;
    int currentPlayerID;
    int startingMoney = 1000;
    std::vector<Player> players;
public:
    // Functions
    void createPlayer() {
        ++currentPlayerID;
        Player newPlayer(currentPlayerID, startingMoney);
        players.push_back(newPlayer);
        ++currentPlayerID;
    }
    void createPlayers(int playerAmount) {
        for (int i = 0; i <= playerAmount; ++i) {
            createPlayer();
        }
    }
    Player getPlayer(int index) {
        Player p = players[index];
        return p;
    }
};
class Player {
private:
    int playerID;
    int money;
    std::vector<int> propertiesOwned;
    void addProperty(int id) {
        this->propertiesOwned.push_back(id);
    }
public:
    // Constructor
    Player(int pID, int sMoney) {
        this->playerID = pID;
        this->money = sMoney;
    }

    // Functions
    Player payMoney(int payAmount, unsigned int destinationID, Game engine) {
        this->money -= payAmount;
        if (destinationID > 0) {
            // Checks if you're paying to a player or bank
            bool playerFound = false;
            for (int i = 0; i <= engine.getPlayerAmount(); ++i) {
                if (engine.getPlayer(i).getID() == destinationID) {
                    playerFound = true;
                    break;
                }
            }
            if (playerFound) {
                // Player was found
                engine.getPlayer(destinationID).giveMoney(payAmount);
                return;
            }
            else {
                std::cout << "\nERROR: Invalid player ID at function payMoney\n";
                return;
            }

        }
        else {
            // You're paying to the bank
        }
        return;
    }
    void buyProperty(int id, int price, Game engine) {
        payMoney(price, 0, engine);
        addProperty(id);
    }
    void giveMoney(int payMoney) {
        this->money += payMoney;
    }

    // Returns
    inline int getMoney() { return this->money; }
    inline int getID() { return this->playerID; }
    inline auto getProperties(int index) {
        auto p = propertiesOwned[index];
        return p;
    }
    inline int getPropertyAmount() {
        int amount = std::size(propertiesOwned);
        return amount;
    }
};
}

Я ожидал, что классы будут нормально выполнять другие классы, но в C ++ похоже, что классы определены в определенном порядке, и вы можете получить доступ только к классам (в классе), объявленным перед тем классом, который вы используете, обратная связь и альтернативы, которые исправят это, помогут

1 Ответ

0 голосов
/ 08 января 2019

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

Во-первых, вы должны поменять местами порядок, в котором определены Game и Player. Это облегчит задачу, поскольку Player зависит от Game меньше раз, чем Game зависит от Player.

Затем добавьте предварительное объявление для Game перед определением Player:

class Game;

Это сообщает компилятору, что класс с именем Game существует, и позволяет использовать его в сценариях, когда ему не нужно знать содержимое (то есть определение) класса.

Затем, payMoney и buyProperty принимают их engine параметр по ссылке вместо по значению , изменяя спецификатор параметра на Game &engine. Это важно по двум причинам. Во-первых, передача по значению может быть выполнена только в том случае, если вы уже определили тип, которого у нас нет (мы только объявили его). Во-вторых, передача по значению создает копию объекта, что в данном случае означает совершенно новый vector совершенно новых Player объектов, и изменения не будут синхронизированы обратно со старым объектом. См. здесь для лучшего объяснения ссылок.

Далее необходимо извлечь определение payMoney, чтобы после определения Game. Причина в том, что хотя список параметров payMoney больше не зависит от определения Game, код в теле функции делает это (потому что он вызывает функции для объекта engine). Посмотрите конец того, как это выглядит.

Это исправляет все проблемы с порядком объявления / определения. Вы также должны сделать payMoney return void, поскольку его возвращаемое значение никогда не предоставляется и никогда не используется, выберите согласованный тип для идентификаторов (либо int или unsigned int, а не микс) и добавьте getPlayerAmount к Game.

Вот как может выглядеть окончательный код:

namespace Monopoly {
    typedef enum { normal, train, company, incometax, luxurytax, start, chancecard, chestcard, jail } type;

    class Game;

    class Player {
    private:
        int playerID;
        int money;
        std::vector<int> propertiesOwned;
        void addProperty(int id) {
            this->propertiesOwned.push_back(id);
        }
    public:
        // Constructor
        Player(int pID, int sMoney) {
            this->playerID = pID;
            this->money = sMoney;
        }

        // Functions
        void payMoney(int payAmount, int destinationID, Game &engine);
        void buyProperty(int id, int price, Game &engine) {
            payMoney(price, 0, engine);
            addProperty(id);
        }
        void giveMoney(int payMoney) {
            this->money += payMoney;
        }

        // Returns
        inline int getMoney() { return this->money; }
        inline int getID() { return this->playerID; }
        inline auto getProperties(int index) {
            auto p = propertiesOwned[index];
            return p;
        }
        inline int getPropertyAmount() {
            int amount = std::size(propertiesOwned);
            return amount;
        }
    };

    class Game {
    private:
        bool running = false;
        int turn = 1;
        int currentPlayerID;
        int startingMoney = 1000;
        std::vector<Player> players;
    public:
        // Functions
        void createPlayer() {
            ++currentPlayerID;
            Player newPlayer(currentPlayerID, startingMoney);
            players.push_back(newPlayer);
            ++currentPlayerID;
        }
        void createPlayers(int playerAmount) {
            for (int i = 0; i <= playerAmount; ++i) {
                createPlayer();
            }
        }
        Player getPlayer(int index) {
            Player p = players[index];
            return p;
        }
        int getPlayerAmount() {
            int amount = players.size();
            return amount;
        }
    };

    void Player::payMoney(int payAmount, int destinationID, Game &engine) {
        this->money -= payAmount;
        if (destinationID > 0) {
            // Checks if you're paying to a player or bank
            bool playerFound = false;
            for (int i = 0; i <= engine.getPlayerAmount(); ++i) {
                if (engine.getPlayer(i).getID() == destinationID) {
                    playerFound = true;
                    break;
                }
            }
            if (playerFound) {
                // Player was found
                engine.getPlayer(destinationID).giveMoney(payAmount);
                return;
            }
            else {
                std::cout << "\nERROR: Invalid player ID at function payMoney\n";
                return;
            }

        }
        else {
            // You're paying to the bank
        }
        return;
    }
}

Примечание: технически лучше использовать C ++ size_t вместо int для переменных, хранящих размер векторов, так как это то, что возвращают функции size (и это целочисленный тип без знака, тогда как int подписано), но это не особенно важно.

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