Вы правы в том, что в 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
подписано), но это не особенно важно.