Программирование >>  Унарные и бинарные операторы 

1 ... 14 15 16 [ 17 ] 18 19 20 ... 37


Здесь а - конкретный объект типа туе lock, он занимает память и в некотором смысле реально существует. Что же касается класса (будем называть так конструкцию class <имя>{}), то это всего лишь идея объекта, его описание. Имея описание, можно создать множество объектов, например массив, состоящий из десяти часов:

myclоск clocks[10]:

Только что созданным объектом можно управлять с помощью его собственных функций. Следующая ин-струк!1ия устанавливает начальное время - 10 часов 59 минут 30 секунд:

a.clockset(10.59,30);

Далее в цикле имитируется ход часов в течение 1000 секунд. После каждого вызова функции a.tickO на экране функцией а .dispO высвечивается время .

Заметим, что наши часы получились игрушечными - это лишь циферблат со стрелками, переводимыми вруч ную. Настоящие часы вызывают функцию а. ti ск () точно раз в секунду. Часам, показанным в листинге 7.2, не хватает самого главного - механизма определения времени.

Завершим этот раздел важным замечанием, помогающим понять природу объектов в С++ и их отличие от объектов реального мира Вспомним, что часы, которые мы носим на руке или в кармане, идут независимо от того, обращаем мы на них внимание или нет. Они автономны, пока не кончится завод или не разрядится батарейка. Совсем не таковы часы, показанные в листинге 7.2. Эти машинные часы все время нужно подталкивать извне, вызывая функцию tick(). Часы не могут уйти в себя , потому что процессор будет занят только их обслуживанием и не сможет отвлечься на что-то другое. Правда, современные операционные систе-

лал многозадачны, и в программе на С++ можно создать несколько независимых объектов, использующих процессор по очереди. Такие объекты могут принимать друг от друга данные и сообщения, но все эти многозадачные операции нестандартны и организуются в разных операционных системах по-разному. К тому же они довольно сложны, и в этой книге, предназначенной для начинающих программистов, мы о них больше говорить не будем.

Карты

Приступая к решению задачи, нужно, прежде всего, думать о том, какие объекты должны быть со,зданы, какими данными будет владеть каждый объект, какие сообщения они будут посылать друг другу. От удачного Подбора объектов во многом зависит общий успех.

Но, к сожалению, не существует самого лучшего способа выделения объектов. Даже опытный программист, проделав значительную часть работы, может понять, что шел по ложному пути и нужно все начинать сначала. Поэтому единственный способ научиться - это программировать самому, причем не так, как можешь, а так, как нужно. Программисты учатся, постоянно переписывая программы и постепенно приближая их к идеалу .

Для примера попробуем наметить контуры программы, играющей в карты. В отличие от других более серьезных задач, где объекты могут быть весьма абстрактными, основные объекты для игры в карты очевид-ИЫ: это карта, колода, игроки и, быть может, некий судья - контролирующий объект, подсчитывающий очки, ставки, ведущий статистику и определяющий победителя.



Начнем с описания основного объекта - ифально!) карты. Будем для простоты считать, что в нашей колоде есть карты, начиная с шестерки. Поэтому объект типа card (класс card) может быть таким, как в листинге 7.3.

Листинг 7.3

char suits[4HB.4.n.T}:

char cds[9]=C6.7.8.9.A. В .Д.К. У}:

class card {

public:

void 5et suit(int s){ suit=S; } void setcnCint c){ cn=c: } char get suit(){ return suits[suit]; } char get cn(){ return cds[cn]; } private; int suit; int cn;

В области pri vate нашего объекта хранятся две целочисленные неременные, sui t (масть, меняется от О до 3) и СП (наименование карты: шестерка , семерка , туз , меняется от О до 8). Конечно, мы привыкли называть карты иначе, не (0,0), а шестерка бубей , по-.этому вне класса размещены два массива, храняпще более привычные человеку обозначения карт. Массив char suits[4] хранит четыре масти Б (бубны), Ч (черви), П (пики), Т (трефы), а массив cds[] - имена карт. Поскольку это массив символов, нельзя было поместить в нем 10 (это ведь два символа). По.это.му десятку заменила буква А. Если первым ставить имя карты, то пара АП будет обозначать десятку пик, а КЧ -короля червей.

Вместо записывания русхких слов латинскими буквами (mast -масть) лучше использовать английские слева: и красивей, и полезней (учимся языку).

Массивы cards[] и cds[] используются двумя собственными функциями класса card: функция get suit() BOSepauiacT масть карты (одну из четырех букв Б , 4Ч , П или Т ), а функция getcnO - ее название. Две другие собственные функции класса card устанавливают значение масти (set suit()) и название карты (set cn()).

Обратите внимание, массивы suits и cds расположены вне класса card, их называют глобальными, и в программе, состоя щей из одного файла, они доступны всюду-из любого объекта, функции main и вообн1е из любой функции. Возникает вопрос: где должны находиться .эти массивы? Правильно ли они сделаны глобальными, всем доступными? По идее, обозначения мастей и карт принадлежат самой карте, но С++ запрещает присваивание значений переменным внутри класса, ведь реальные переменные со значениями есть только у объекта, а класс - это всего лишь описание объекта. Поэтому нам придется оставить массивы cards[] и cds[] вне описания объекта card.

После определения карты можно подумать о колоде и связанных с ней собственных функциях. Очевидно, колоду нужно тасовать, а также вынимать из нее Карты для раздачи игрокам. Поскольку карты при раздаче снимаются сверху, для колоды больше всего подойдет контейнерный тин под названием deque (дву-рторо!П1яя очередь), похожий на vector, но позволяющий удалять и добавлять элементы с обоих концов. То есть карты можно будет вынимать сверху и снизу и точно так же возвращать в колоду. Описание колоды, показанное в листинге 7.4, содержит три собственные функции:

+ iniO - создание колоды; + shuffleO - тасование;

getO - снятие карты с верха колоды.



Листинг 7.4

class с1еск{ public: void ini(){ card tmp:

forCint i=0:i<9:i++) fordnt j-0:j<4:j++){

tmp.set suit(j):

tmp.set cn(i):

d.push back(tmp):

shuffleO:

void shuffle(){

randora shuffle(d.begin().d.end()):

card get(){

card tmp-d.frontO: d.popfrontO: return trrp:

private:

deque<card> d:

Функция ini ()создает колоду, где сначала располагаются бубны, начиная с шестерки и кончая тузом, затем черви и т. д. Далее колода тасуется функцией randora shuffle().

Функция get О создает временную переменную temp, затем переписывает в нее первую карту колоды (tmp=d. front()), а потом эга карта удаляется из колоды функцией d. pop f ront ().

Чтобы вынуть последнюю карту колоды, нужны следующие инструкции:

trap-d.backO: прочитать последнюю карту

d.pop back(): удалить последнюю карту

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

колоду из 52 карт, пригодную для любой карточной игры.

в этом ра.зделе нам, конечно, не удастся создать полноценную программу, играющую в карты. Эта задача слишком сложна, поэтому ограничимся раздачей карт, предположив, что игроки будут играть в козла - одну из самых примитивных карточных игр. Но перед раздачей необходимо описать еще один объект - самого игрока (объект player). У нас он будет очень простым: с функциями showO (показать карты), ini О (подготовиться к раздаче карт) и add() (взять карту из колоды). Описание объекта р1 ауег приведено в листинге 7.5.

Листинг 7.5

class р1ауег{ public: void show(){

for(unsigned i=0:i<h.size():i++) cout h[i].get cn() ;

cout endl:

forCunsigned i=0:i<h.sized:i++) cout h[i].get suit() : cout endl endl:

void 1ni(){ h.clearO:

void addCcard c){ h.push back(c):

- private:

deque<card> h:

Как видим, карты игрока, как и в целой колоде, хранит контейнер deque<card>. Функция h.clearO, используемая в функции ini О, очищает контейнер, а функция *i.push backO добавляет в него карту.



1 ... 14 15 16 [ 17 ] 18 19 20 ... 37

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика