2016-12-28 6 views
0

Я реализую игру Монополия в C++. Я имею дело с абстрактным суперклассом BoardSquare (чье единственное свойство - это квадратное имя), с различными подклассами в зависимости от типа игрового квадрата (будь то свойство, шанс и т. Д.)Вызов метода подкласса из массива объектов суперкласса

Теперь, поскольку я хочу представлять доска как массив и квадраты различаются по типам, я объявил массив BoardSquare указателей:

GameSquare** board = new GameSquare*[40]; 

и продолжала заполнять каждую запись в зависимости от типа:

board[1] = new Property("Old Kent Road", 0); 
board[2] = new CommunityChest(); 
board[3] = new Property("Whitechapel Road", 0); 

и так далее.

В настоящее время Property, например, имеет специальные методы, такие как getPrice(). Но работает

board[1]->getPrice() 

дает ошибку

«класса GameSquare» не имеет элемента с именем «getPrice»

, который говорит мне, что указатель все еще рассматривается как GameSquare. Есть ли способ обойти это? Может быть? или более элегантная реализация?

+0

Вам нужно будет проверить тип вашего экземпляра, чтобы он мог передать его в подтип, чтобы вызвать базовый метод. – Piou

+1

@Piou Не могли бы вы привести синтаксический пример? Например, я знаю, что 'board [1]' является свойством, поэтому я могу запустить '((Property *) board [1]) -> getPrice()'? –

+0

Другим решением было бы реализовать виртуальный метод 'getPrice' в классе GameSquare, который возвращает -1, переопределяя его в' Property', чтобы вернуть цену, переданную конструктору. Затем в вашей логике отображения вы просто проверяете, что цена> 0, чтобы отобразить информацию. – Piou

ответ

2

Это отличный пример object slicing.

Предложение 1: Динамический Downcast

Один из способов предотвратить это, чтобы добавить следующее:

Property *b1 = dynamic_cast<Property*>(board[index]); 
if (b1) 
{ 
    int b = b1->getPrice(); // Or whatever getPrice() returns; 
} 

Однако, вы должны попробовать динамический потупив для каждого подкласса (Property, CommunityChest, и т. д.), и это может сделать код неудобным для вас.

Предложение 2: Добавить getPrice() для GameSquare

Как предложили несколько комментаторов, вы можете добавить метод getPrice() к GameSquare классу. Если квадрат не является Property, просто верните 0. Это позволяет проверить, есть ли что-то Property или что-то еще.

1

Вы, безусловно, можете делать то, о чем просите, но тот факт, что вы должны это сделать, означает, что вы нарушаете правила дизайна OO.

Я бы предложил посмотреть на каждый квадрат с точки зрения действий, которые игрок может выполнить на нем, таких как покупка, заклад, получение карты, пропуск. Некоторые действия могут быть автоматическими, когда игрок приземляется на квадрат. Некоторые могут быть представлены в графическом интерфейсе.

Таким образом, вы не должны знать, что квадрат имеет цену - вы просто предлагаете игроку возможность купить действие, и действие знает, что это свойство. Если собственность принадлежит игроку, теперь она получает действие «построить дом». И так далее.

Квадрат имел бы метод вдоль линий vector<ActionPtr> getActionsFor(PlayerPtr player).

+0

Мне нравится это решение, вот как я мог бы реализовать его на C# или JS, однако я был недостаточно подготовлен, чтобы предлагать фрагмент кода в C++ – Piou