|
Программирование >> Унарные и бинарные операторы
Здесь а - конкретный объект типа туе 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 добавляет в него карту.
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |