В разделах «Размышления об объектах» глав с 1 по 5 мы познакомились с основами объектного ориентирования и провели объектно-ориентированное проектирование модели лифта. В рамках главы 6 мы познакомились с деталями программирования и использования классов на языке С++. К настоящему моменту вы готовы (и, возможно, страстно желаете) начать программирование вашей модели лифта.
Лабораторное задание 5 по лифту
Для каждого класса, который вы выделили в разделах «Размышления об объектах» глав со 2 по 5, напишите соответствующие определения классов на С++. Для каждого класса включите как заголовочный файл, так и исходный файл определения функций-элементов.
Напишите программу драйвера, который проверяет каждый из этих классов и пытается запустить на выполнение полную модель лифта. ПРЕДУПРЕЖДЕНИЕ: возможно, вам придется подождать, пока вы не изучите главу 7 «Классы: часть II» , прежде чем вы будете в состоянии создать приемлемо работающую версию вашей модели. Так что будьте терпеливы и реализуйте только те части модели лифта, для которых вам хватает знаний, приобретенных в главе 6. В главе 7 вы узнаете о композиции, т.е. о создании классов, которые содержат другие классы в качестве элементов; эта техника могла бы помочь вам представить, например, объект кнопку внутри лифта как элемент лифта. Кроме того, в главе 7 вы узнаете, как динамически создавать и уничтожать объекты с помощью new и delete; это поможет вам создавать новые объекты пассажиров, когда они должны появиться в модели, и уничтожать эти объекты пассажиров, когда они покидают модель (после выхода пассажира из лифта).
Для первой версии вашей модели спроектируйте только простой вывод, ориентированный на текст, который отобразит сообщения о каждом существенном событии, которое будет происходить. Ваши сообщения могли бы включать такие строки, как «Пассажир 1 прибывает на Этаж 1», «Пассажир 1 нажимает Кнопку «Вверх» Этажа 1», «Лифт прибывает на Этаж 1», «Пассажир 1 входит в Лифт» и т.д. Заметим, что мы рекомендуем вам печатать с заглавной буквы те слова каждого сообщения, которые представляют объекты вашей модели. Заметим также, что вы можете предпочесть отложить эту часть лабораторного занятия до прочтения главы 7.
Наиболее амбициозные студенты захотят использовать анимизирован- ный графический выход, который показывает, как модель лифта движется на экране вверх и вниз.
Резюме
Структуры — это совокупности типов данных, построенные с использованием данных других типов.
Ключевое слово struct начинает определение структуры. Тело структуры заключается в фигурные скобки ({ и }). Каждое определение структуры должно заканчиваться точкой с запятой.
Тэг (имя-этикетка) структуры может использоваться для объявления переменных данного типа структуры.
Определения структуры не резервируют место в памяти; они создают новые типы данных, которые используются далее для объявления переменных.
Элементы структуры или класса доступны при использовании операций доступа к элементу — операции точка (.) и операции стрелка (->).
Операция точка обеспечивает доступ к элементу структуры посредством имени переменной объекта или ссылки на объект. Операция стрелка обеспечивает доступ к элементу структуры посредством указателя на объект.
Препятствиями к созданию новых типов данных с помощью struct являются: возможность существования данных, не имеющих начальных значений; возможность существования данных с неправильными начальными значениями; необходимость изменения всех программ, использующих struct, при изменении реализации struct; отсутствие средств защиты, гарантирующих, что данные не содержат несогласованных значений.
Классы предоставляют программисту возможность моделировать объекты с атрибутами и различными вариантами поведения. Типы классов можно определять в С++ , используя ключевые слова class и struct, но обычно для этих целей используется ключевое слово class.
Имя класса можно использовать для объявления объектов этого класса.
Определения класса начинаются с ключевого слова class. Тело определения класса заключается в фигурные скобки ({ и }). Определение класса заканчивается точкой с запятой.
Любые данные-элементы или функции-элементы, объявленные в классе после метки public:, являются открытыми и видимыми для любой функции, для которой доступен объект данного класса.
Любые данные-элементы или функции-элементы, объявленные в классе после метки private:, являются закрытыми и видимыми только друзьям и другим элементам класса.
Метки доступа к элементу всегда заканчиваются двоеточием (:) и могут появляться в определении класса неоднократно и в любой последовательности.
Закрытые данные недоступны вне класса.
Говорят, что реализация класса скрыта от его клиентов.
Конструктор — это специальная функция-элемент с тем же именем, что и класс, которая используется для инициализации элементов объекта класса. Конструкторы вызываются при создании объектов соответствующих классов.
Функция с тем же именем, что и класс, но предваряемая знаком тильды (-), называется деструктором.
Набор открытых функций-элементов класса называется интерфейсом класса или открытым интерфейсом.
Если функция-элемент определена вне определения данного класса, имя функции предваряется именем класса и бинарной операцией разрешения области действия (::).
Функции-элементы, определенные с использованием операции разрешения области действия вне определения класса, имеют областью действия этот класс.
Функции-элементы, определенные в определении класса, автоматически встраиваются inline. Компилятор сохраняет право не встраивать любую функцию.
Вызов функций-элементов более компактен, чем вызов функций в процедурном программировании, потому, что большинство данных, используемых в функции-элементе, непосредственно доступно ей в объекте.
Внутри области действия класс на элементы класса можно ссылаться просто с помощью их имен. Вне области действия класс на элементы класса можно ссылаться посредством либо имени объекта, либо ссылки на объект, либо указателя на объект.
Для доступа к элементам класса используются операции . и ->.
Фундаментальный принцип разработки хорошего программного обеспечения состоит в отделении интерфейса от реализации для улучшения модифицируемости программы.
Определения класса обычно помещаются в заголовочных файлах, а определения функций-элементов — в файлах исходных кодов, имеющих такое же имя.
По умолчанию способ доступа в классах — private, так что все элементы после заголовка класса и до первого спецификатора доступа считаются закрытыми.
Открытые элементы класса предоставляют набор услуг, которыми класс обеспечивает своих клиентов.
Доступом к закрытым данным класса можно эффективно управлять с помощью функций-элементов, называемых функциями доступа. Если класс хочет позволить клиентам читать закрытые данные, он может обеспечить это с помощью функций чтения «get». Изменять закрытые данные класс может позволить своим клиентам с помощью функций записи «set».
Данные-элементы класса обычно делаются закрытыми, а функции-элементы — открытыми. Некоторые функции-элементы могут быть закрытыми и играть роль функций-утилит для других функций класса.
Данным-элементам класса нельзя задавать начальные значения в определении класса. Они должны получать начальные значения в конструкторе или же их значения могут быть установлены после создания соответствующего объекта.
Конструкторы можно перегружать.
После того, как объект класса получил соответствующие начальные значения, все функции-элементы, которые манипулируют объектом, должны давать гарантию, что объект остается в непротиворечивом состоянии.
В объявлении объекта класса могут быть предусмотрены начальные значения. Эти начальные значения передаются конструктору класса.
Конструкторы могут определять аргументы по умолчанию.
Конструкторы не могут ни указывать тип возвращаемых значений, ни пытаться возвращать значения.
Если для класса не определено никаких конструкторов, компилятор создает конструктор с умолчанием. Такой конструктор не выполняет присваивания никаких начальных значений, так что после создания объекта нет гарантий, что он находится в непротиворечивом состоянии.
Деструктор автоматического объекта вызывается при выходе из области действия объекта. Сам по себе деструктор в действительности не уничтожает объект, но он выполняет подготовку его уничтожения перед тем, как система использует память объекта, которую ранее занимал объект.
Деструкторы не получают параметров и не возвращают значений. Класс может иметь только один деструктор.
Операция присваивания (=) используется для присваивания объекта другому объекту того же типа. Такое присваивание обычно выполняется с помощью побитового копирования по умолчанию. Побитовое копирование не является идеальным для всех классов.
Терминология
class private: protected: public:
абстрактный тип данных атрибут
бинарная операция разрешения области действия (::) встраиваемая inline функция-элемент вхождение в область действия выход из области действия глобальный объект данные-элементы деструктор заголовочный файл закрытые элементы инициализация объекта класса инкапсуляция интерфейс класса исходный файл класс
клиент класса конструктор
конструктор с умолчанием набор функций непротиворечивое состояние данных-элементов нестатический локальный объект область действия класс область действия файл объект
объектно-ориентированное программирование (ООП) операция доступа к элементу класса (.)
операция разрешения области действия (::) операция ссылки & определение класса открытые элементы открытый интерфейс класса побитовая копия поведение
повторно используемый код повторное использование программного обеспечения предикатная функция принцип наименьших привилегий процедурное программирование расширяемость реализация класса скрытие информации сообщение
спецификаторы доступа к элементам список инициализации элементов статический локальный объект тильда (-) в имени деструктора тип данных
тип, определяемый пользователем управление доступом к элементам ускоренная разработка приложений (RAD)
услуги класса функция доступа функция записи (set) функция запроса функция не элемент класса функция чтения (get) функция-утилита функция-элемент экземпляр объекта класса
Типичные ошибки программирования
Забывается точка с запятой в конце определения класса (или структуры).
Попытка явно присвоить начальное значение данным-элементам в определении класса.
Попытка перегрузить функцию-элемент класса с помощью функции не из области действия этого класса.
Попытка с помощью функции, не являющейся элементом определенного класса (или другом этого класса) получить доступ к элементам этого класса.
Попытка объявить тип возвращаемого значения для конструктора или возвратить значение из конструктора.
Указание начальных значений по умолчанию для одной и той же функции-элемента как в заголовочном файле, так и в описании функции-элемента.
Попытки передать аргументы деструктору, вернуть значения из деструктора или перегрузить деструктор.
Конструктор может вызывать другие функции-элементы класса такие, как функции записи и чтения. Но поскольку конструктор инициализирует объект, данные-элементы могут в этот момент еще не быть в непротиворечивом состоянии. Использование данных-эле- ментов до того, как они получили соответствующие начальные значения, может вызвать ошибки.
Хороший стиль программирования
Используйте при определении класса каждый спецификатор доступа к элементам только один раз, что сделает программу более ясной и простотой для чтения. Размещайте первыми элементы public, являющиеся общедоступными.
Используйте директивы препроцессора #ifndef, #define и #endif для того, чтобы избежать включения в программу заголовочных файлов более одного раза.
Используйте имя заголовочного файла с символом подчеркивания вместо точки в директивах препроцессора #ifndef и #define заголовочного файла.
Если вы намереваетесь сначала перечислить в определении класса закрытые элементы, используйте явно метку private, несмотря на то, что private предполагается по умолчанию. Это облегчит чтение программы. Но мы предпочитаем первым в определении класса помещать список открытой части public.
Несмотря на то, что спецификаторы public и private могут повторяться и чередоваться, перечисляйте сначала все элементы класса открытой группы, а затем все элементы закрытой группы. Это кон- центрирует внимание клиентов класса в большей степени на его открытом интерфейсе, чем на реализации класса.
Использование спецификаторов доступа к элементам public, protected и private лишь по одному разу в любом определении класса позволяет избежать путаницы.
В соответствующих случаях (почти всегда) предусматривайте конструктор для уверенности в том, что каждый объект получил соответствующие, имеющие смысл начальные значения.
Каждая функция-элемент (или дружественная функция), которая изменяет исходные данные-элементы, должна гарантировать, что данные остаются в не противоречащем друг другу согласованном состоянии.
Объявляйте аргументы функции по умолчанию только в прототипе функции внутри определения класса в заголовочном файле.
Функции-элементы, которые записывают значения закрытых данных, должны проверять правильность предполагаемых новых значений; если они неправильные то эти функции должны установить закрытые данные-элементы в соответствующее им непротиворечивое состояние.
Никогда не возвращайте из открытой функции-элемента неконстантную ссылку (или указатель) на закрытый элемент данных. Возвращение такой ссылки нарушает инкапсуляцию класса.
Советы по повышению эффективности
Обычно структуры передаются вызовом по значению. Чтобы избежать накладных расходов на копирование структуры, передавайте структуры вызовом по ссылке.
Чтобы избежать накладных расходов вызова по значению и вдобавок получить выгоды защиты исходных данных от изменения, передавайте аргументы большого размера как ссылки const.
Описание небольших функций-элементов внутри определения класса автоматически встраивает функцию-элемент inline (если компилятор решит делать это). Это может улучшить производительность, но не способствует улучшению качества проектирования программного обеспечения.
Передача объекта вызовом по значению хороша с точки зрения безопасности, поскольку вызываемая функция не имеет доступа к исходному объекту, но вызов по значению может ухудшить производительность в случае создания копии большого объекта. Объект может быть передан вызовом по ссылке путем передачи либо указателя, либо ссылки на объект. Вызов по ссылке способствует хорошей производительности, но с точки зрения безопасности хуже предыдущего, поскольку функции предоставлен доступ к исходному объекту. Безопасной альтернативой является вызов со ссылкой const.
Замечания по технике программирования
Важно писать программы, которые легко понимать и поддерживать. Изменения являются скорее правилом, чем исключением. Программисты должны предвидеть, что их коды будут изменяться. Как мы увидим, классы способствуют модифицируемости программ.
Клиенты класса используют класс, не зная внутренних деталей его реализации. Если реализация класса изменяется (например, с целью улучшения производительности), интерфейс класса остается неизменным и исходный код клиента класса не требует изменений. Это значительно упрощает модификацию систем.
Функции-элементы обычно короче, чем обычные функции в программах без объектной ориентации, потому что достоверность данных, хранимых в данных-элементах, идеально проверена конструктором и функциями-элементами, которые сохраняют новые данные.
Клиенты имеют доступ к интерфейсу класса, но не имеют доступа к реализации класса.
Объявление функций-элементов внутри определения класса и описание функций-элементов вне этого определения отделяет интерфейс класса от его реализации. Это способствует высокому качеству разработки программного обеспечения.
Использование принципов объектно-ориентированного программирования часто может упростить вызовы функции за счет уменьшения числа передаваемых параметров. Это достоинство объектно-ориентированного программирования проистекает из того факта, что инкапсуляция данных-элементов и функций-элементов внутри объекта дает функциям-элементам право прямого доступа к данным- элементам.
Помещайте объявление класса в заголовочный файл, чтобы оно было доступно любому клиенту, который захочет использовать класс. Это формирует открытый интерфейс класса. Помещайте определения функций-элементов класса в исходный файл. Это формирует реализацию класса.
Клиенты класса не нуждаются в доступе к исходному коду класса для того, чтобы использовать класс. Однако, клиенты должны иметь возможность связаться с объектным кодом класса.
Информация, важная для интерфейса класса, должна включаться в заголовочный файл. Информация, которая будет использоваться только внутри класса и которая не является необходимой для клиентов класса, должна включаться в неоглашаемый исходный файл. Это еще один пример принципа наименьших привилегий.
С++ способствует созданию программ, не зависящих от реализации. Если, изменяется реализация класса, используемого программой, не зависящей от реализации, то код этой программы не требует изменения, но может потребоваться его перекомпиляция.
Делайте все данные-элементы класса закрытыми. Используйте открытые функции-элементы для задания и получения значений закрытых данных-элементов. Такая архитектура помогает скрыть реализацию класса от его клиентов, что снижает число ошибок и улучшает модифицируемость программ.
Разработчики классов используют доступ типа public, protected или private, чтобы обеспечить скрытие информации и принцип наименьших привилегий.
Разработчик класса не обязательно должен снабжать каждый элемент закрытых данных функциями get и set; такие возможности должны быть обеспечены, только тогда, когда это имеет смысл, и лишь после тщательного обдумывания разработчиком класса.
Задание данных-элементов класса закрытыми, а функций-элементов класса открытыми облегчает отладку, так как проблемы с манипуляциями данных локализуются в рамках либо функций-элементов класса, либо друзей класса.
Функции-элементы можно разбить на ряд категорий: функции, которые читают и возвращают значения закрытых данных-элементов; функции, которые устанавливают значения закрытых данных-элементов; функции, которые реализуют возможности класса; функции, которые выполняют для класса различные вспомогательные операции, такие, как задание начальных значений объектам класса, присваивания объектам класса, преобразования между классами и встроенными типами или между классами и другими классами, выделение памяти для объектов класса.
Если функция-элемент класса уже обеспечивает все или часть функциональных возможностей, требуемых конструктором (или другой функцией-элементом), вызывайте эту функцию-элемент из конструктора (или другой функции-элемента). Это упрощает сопровождение программы и уменьшает вероятность ошибки при изменении реализации кода.
Задание закрытых данных-элементов и управление доступом к ним, особенно доступом к записи данных-элементов, посредством открытых функций-элементов помогает гарантировать целостность данных.
Доступ к закрытым данным посредством функций записи и чтения не только защищает данные-элементы от присваивания им неправильных значений, но и отделяет клиентов класса от внутреннего представления данных-элементов. Таким образом, если внутреннее представление этих данных по каким-либо причинам (обычно из-за требований сокращения объема памяти или повышения производительности) изменяется, достаточно изменить только функ- ции-элементы, а клиентам не требуется вносить никаких изменений, пока остается неизменным интерфейс функций-элементов. Однако, возможно, потребуется перекомпиляция клиентов данного класса.
Упражнения для самопроверки
6.1. Заполнить пробелы в следующих утверждениях:
Ключевое слово ___________ начинает определение структуры.
Элементы класса доступны посредством операции_______________ в сочетании с объектом класса или посредством операции ___________________________________________________ в сочетании с указателем на объект класса.
Элементы класса, указанные как__________ , доступны только функциям-элементам класса и друзьям класса.
является специальной функцией-элементом, используемой
для задания начальных значений элементам данных класса.
По умолчанию доступ к элементам класса — _______________ .
Функция _________ используется для присваивания значений закрытым данным-элементам класса.
можно использовать для присваивания объекта класса
другому объекту того же класса.
Функции-элементы класса обычно делаются _______________ типа, а
данные-элементы — ____________ типа.
Функция__________ используется для получения значений закрытых данных класса.
j) Набор открытых функций-элементов класса рассматривается как класса.
к) Говорят, что реализация класса скрыта от его клиентов или
1) Для введения определения класса можно использовать ключевые слова и .
т) Элементы класса, указанные как _______________ , доступны везде в
области действия объекта класса.
6.2. Найдите ошибку (или ошибки) в каждом из следующих пунктов и объясните, как их исправить.
Допустим, что в классе Time объявлен следующий прототип.
void ~Time(int);
Следующий фрагмент является частью определения класса Time.
class Time { public;
// прототипы функций private:
int hour = 0; int minute = 0; int second = 0;
} ;
Допустим, что в классе Employee объявлен следующий прототип.
int Employee(const char *, const char *);
Ответы на упражнения для самопроверки
a) struct, b) точка (.), стрелка (->). с) private, d) Конструктор. e)pri- vate. f) записи «set», g) Поэлементное копирование по умолчанию (с помощью операции присваивания), h) открытого, закрытого, i) чтения «get», j) интерфейс, к) инкапсулирована. 1) class, struct, m) public.
а) Ошибка: Деструкторы не могут возвращать значения или принимать аргументы.
Исправление: переместите тип void возвращаемого значения и параметр int из определения.
Ошибка: элементы не могут явно получать начальные значения в определении класса.
Исправление: уберите явное задание начальных значений из определения класса и задавайте начальные значения элементов в конструкторе.
Ошибка: конструкторы не могут возвращать значения. Исправление: переместите тип int возвращаемого значения из объявления.
Упражнения
Каково назначение операции разрешения области действия?
Сравните и сопоставьте нотацию struct и class в С++.
Создайте конструктор, способный использовать текущее время, даваемое функцией time(), объявленной в заголовочном файле time.h стандартной библиотеки С, чтобы задавать начальные значения объекту класса Time.
Создайте класс с именем Complex для выполнения арифметических действий с комплексными числами. Напишите программу драйвера для проверки вашего класса.
Комплексные числа имеют форму
realPart + imaginaryPart *j где j — квадратный корень из -1.
Используйте переменные с плавающей запятой для представления закрытых данных этого класса. Создайте функцию конструктор, которая позволяет объекту этого класса принимать начальные значения при его объявлении. Создайте открытые функции-элементы для каждого из следующих пунктов:
Сложение двух комплексных чисел: отдельно складываются действительные и мнимые части.
Вычитание двух комплексных чисел: действительная часть правого операнда вычитается из действительной части левого операнда, а мнимая часть правого операнда вычитается из мнимой части левого операнда.
Печать комплексных чисел в форме (а, Ь), где а — действительная часть, a b — мнимая часть.
Создайте класс по имени Rational для выполнения арифметических действий с дробями. Напишите программу драйвера для проверки вашего класса.
Используйте целые переменные для представления закрытых данных класса — числителя и знаменателя. Создайте функцию конструктор, которая позволяет объекту этого класса принимать начальные значения при его объявлении. Конструктор должен содержать значения по умолчанию на случай отсутствия заданных начальных значений и должен хранить дроби в сокращенном виде (т.е. дробь 2/4 должна храниться в объекте как 1 в числителе и 2 в знаменателе). Создайте открытые функции-элементы для каждого из следующих случаев:
Сложение двух чисел Rational. Результат должен храниться в сокращенной форме.
Вычитание двух чисел Rational. Результат должен храниться в сокращенной форме.
Перемножение двух чисел Rational. Результат должен храниться в сокращенной форме.
Деление двух чисел Rational. Результат должен храниться в сокращенной форме.
Печать чисел Rational в форме а / Ь, где а — числитель, a b — знаменатель.
Печать чисел Rational в форме с плавающей точкой.
Модифицируйте класс Time на рис. 6.10 так, чтобы включить функ- цию-элемент tick, которая дает приращение времени, хранящегося в объекте Time, равное одной секунде. Объект Time должен всегда находиться в непротиворечивом состоянии. Напишите программу- драйвер для проверки функции-элемента tick в цикле, которая печатала бы время в стандартном формате на каждой итерации цикла и иллюстрировала правильную работу функции-элемента tick. Удостоверьтесь в правильности работы в следующих случаях:
Приращение с переходом в следующую минуту.
Приращение с переходом в следующий час.
Приращение с переходом в следующий день (т.е. от 11:59:59 РМ к 12:00:00 AM).
Модифицируйте класс Date на рис.6.12 так, чтобы выполнить проверку ошибки в списке начальных значений для данных-элементов month, day и year. Кроме того, создайте функцию-элемент nextDay, которая бы увеличивала день на единицу. Объект Date должен всегда находиться в непротиворечивом состоянии. Напишите програм- му-драйвер, проверяющую функцию nextDay в цикле и печатающую время в стандартном формате на каждой итерации цикла, чтобы проиллюстрировать правильную работу функции nextDay. Удостоверьтесь в правильности работы в следующих случаях:
Приращение с переходом в следующий месяц.
Приращение с переходом в следующий год.
Объедините модифицированный класс Time упражнения 6.8 и модифицированный класс Date упражнения 6.9 в один класс по имени DateAndTime (в главе 9 мы обсудим наследование, которое позволит нам быстро решить эту задачу без изменения существующих определений классов). Модифицируйте функцию tick так, чтобы вызывать функцию nextDay, если время получает приращение с переходом на следующий день. Модифицируйте функции PrintStandard и PrintMilitary, чтобы выводить в добавление к времени еще и дату. Напишите программу-драйвер, проверяющую новый класс DateAndTime. Особо проверьте приращение времени с переходом на следующий день.
Модифицируйте набор функций в программе на рис. 6.10 так, чтобы возвращать ошибочные значения в случае попытки задать неправильные значения данным-элементам объекта класса Time.
Создайте класс Rectangle (прямоугольник). Класс имеет атрибуты length (длина) и width (ширина), каждый из которых по умолчанию равен 1. Он имеет функции-элементы, которые вычисляют периметр (perimeter) и площадь (area) прямоугольника. Он имеет функции записи и чтения как для length, так и для width. Функции записи должны проверять, что length и width — числа с плавающей запятой, находящиеся в пределах от 0.0 до 20.0.
Создайте более изощренный, чем в упражнении 6.12, класс Rectangle. Этот класс хранит только декартовы координаты четырех углов прямоугольника. Конструктор вызывает набор функций, которые принимают четыре группы координат и проверяют, чтобы каждая из координат х и у находилась в первом квадранте, в диапазоне от 0.0 до 20.0. Это множество функций должно также проверять, что переданные координаты действительно определяют прямоугольник. Должны быть предусмотрены функции-элементы, вычисляющие length, width, perimeter, и area. Длиной должно считаться большее из двух измерений. Включите предикатную функцию square, которая определяла бы, не является ли прямоугольник квадратом.
Модифицируйте класс Rectangle в упражнении 6.13 так, чтобы включить в него функцию draw, которая изображает прямоугольник внутри окна 25 на 25, перекрывающего часть первого квадранта, в котором находится прямоугольник. Включите функцию setFill- Character, чтобы задавать символ, которым будет заполняться прямоугольник внутри. Включите функцию setPerimeterCharacter, чтобы задавать символ, которым будут печататься границы прямоугольника. Если вы войдете во вкус, вы можете включить функции масштабирования размера прямоугольника, его вращения и перемещения в пределах первого квадранта.
Создайте класс Hugelnteger, который использует массив из 40 элементов для хранения целых чисел вплоть до больших целых, содержащих по 40 цифр. Создайте функции-элементы inputHugelnteger, outputHugelnteger, addHugelntegers и substrac- tHugelntegers для ввода, вывода, сложения и вычитания этих больших целых. Для сравнения объектов Hugelnteger создайте функции isEqualTo, isNotEqualTo, isGreaterThan, isLessThan, is- GreaterThanOrEqualTo, isLessThanOrEqualTo — каждая из них является предикатной функцией, которая просто возвращает 1 (истина), если соответствующее соотношение между двумя большими целыми выполняется, и О (ложь) — если оно не выполняется. Создайте предикатную функцию isZero. Если вы войдете во вкус, подготовьте также функции-элементы multiplayHugelntegers, divide- Hugelntegers и modulusHugelntegers.
6.16. Создайте класс TicTacToe, который предоставит вам возможность написать полную программу для игры в тик-так-тоу. Класс содержит как закрытые данные двумерный массив целых чисел 3 на 3, описывающий доску для игры. Конструктор должен присваивать нулевые начальные значения всем пустым полям. Играют два игрока. Помещайте 1 в клетку, указываемую при перемещении первым игроком, и 2 в клетку, указываемую вторым игроком. Каждое перемещение допустимо только на пустую клетку. После каждого перемещения определяйте, не выиграна ли игра или не получилась ли ничья. Если вы вошли во вкус, модифицируйте вашу программу так, чтобы компьютер выполнял перемещения за одного из игроков автоматически. При этом позвольте игроку указывать, хотел бы он или она ходить первым или вторым. Если же вы почувствовали исключительное увлечение, развивайте программу так, чтобы играть в трехмерный тик-так-тоу на доске 4 на 4 на 4 (Предупреждение: это чрезвычайно сложный проект, который может потребовать многонедельных усилий!).
Комментариев нет:
Отправить комментарий