В этом случае вам придется каждый раз выполнять приведение или создавать поле / переменную более определенного типа.
Я не уверен, где вы находитесь, но будьте осторожны с этим дизайном. Часто это признак того, что вы неправильно использовали наследование.
Если вам нужно вызвать новый метод для подкласса, потому что он нужен для какой-то задачи, определенной в суперклассе, это означает, что подкласс нарушает контракт своего родителя (принцип подстановки Google Liskovs).
Если у подкласса действительно есть какая-то новая функциональность, которая не переплетается с родительской функциональностью, вы можете явно использовать подкласс с самого начала (то есть объявление переменной). Или, если это не совсем связано, вам, вероятно, следует использовать новый класс и состав вместо наследования.
Это довольно широко, но как насчет этого дизайна для карточной игры. Я предполагаю, что это сложная игра с несколькими ходами, которая должна проверить, действителен ли ход, и кто его использует. Я не совсем уверен, какую игру вы имеете в виду, выбрасывая, добавляя или удаляя карты.
- Создайте класс Player, но у него не будет намного больше, чем имя. Это также может иметь коллекцию карт.
- Другим классом является GameController, который координирует происходящее и проверяет правила. Это могут быть такие методы как:
- playCard (игрок, карта), которая проверяет ход и добавляет карту к уловке, помня, кто ее сыграл.
- score (), который вычисляет счет в конце каждого хода.
- Другой класс - CPUController. Вот где живет ИИ.
- Наконец, основной цикл.
Основной цикл может работать так:
controller.shuffle();
// Either of:
// 1. push: controller.shuffle() calls player.pickupCards(cards)
// 2. pull: main loop calls player.pickupCards() which in turn calls controller.giveMeMyCards()
while(playersHaveMoreCards()) {
awaitPlayerMove();
// Now is the only time when player can make a move. If there is some
// GUI the main loop could `wait()` on a mutex (until it's awoken when
// player makes move), in text mode it could simply await input from keyboard.
// When player makes a move, it calls controller.playCard(player, card)
cpuController.move();
// Again, when it controller calculates its move, eventually it simply calls controller.playCard()
controller.score();
}
announceWinner(controller.getScore());
Теперь вот что вы получаете с этим подходом:
- Все, что связано с правилами игры и подсчетом очков, находится в одном месте, и это единственное, что есть в GameController. Это очень легко понять и поддерживать.
- То же самое относится к процессору AI. Это все в одном месте, и единственное, что есть в CPUController - это реализация AI.
- Снаружи контроллер точно такой же, независимо от того, есть ли у вас человек против процессора, процессор против процессора или человек против человека. Если вам нужен многопользовательский режим, единственное, что вы можете изменить здесь, - это основной цикл (и это тривиальное изменение).
- Если вы хотите реализовать еще одну хитрую игру, возможно, единственное, что вы измените, это GameController (разные правила) и CPUController (другой AI).
- Если вам нужна другая реализация AI (скажем, более умный алгоритм), вы можете сделать это, только заменив CPUController.
В последних двух случаях наследование имело бы смысл. Вы хотите, чтобы CPUController и GameController имели одинаковый интерфейс (разный для каждого), чтобы основной цикл и Player могли беспрепятственно работать с различными реализациями контроллеров.
Если вы хотите узнать больше об этих принципах проектирования, воспользуйтесь Google для SOLID. Все кончено в этом примере. : -)