Чтение онлайн

ЖАНРЫ

Программирование. Принципы и практика использования C++ Исправленное издание
Шрифт:

19. Зачем делать функции-члены чисто виртуальными?

20. Что такое замещение?

21. Чем наследование интерфейса отличается от наследования реализации?

22. Что такое объектно-ориентированное программирование?

Термины

Упражнения

1. Определите два класса,

Smiley
и
Frowny
, производные от класса
Circle
и рисующие два глаза и рот. Затем создайте классы, производные от классов
Smiley
и
Frowny
, добавляющие к каждому из них свою шляпу.

2. Попытайтесь скопировать объект класса

Shape
. Что
произошло?

3. Определите абстрактный класс и попытайтесь определить объект его типа. Что произошло?

4. Определите класс

Immobile_Circle
, напоминающий класс
Circle
, объекты которого не способны перемещаться.

5. Определите класс

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

6. Определите класс

Striped_circle
, используя приемы из класса
Striped_rectangle
.

7. Определите класс

Striped_closed_polyline
, используя приемы из класса
Striped_rectangle
(для этого придется потрудиться).

8. Определите класс

Octagon
, реализующий правильный восьмиугольник. Напишите тестовую программу, выполняющую все его функции-члены (определенные вами или унаследованные от класса
Shape
).

9. Определите класс

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

10. Определите класс

Pseudo_window
, напоминающий класс
Window
. Постарайтесь не прилагать героических усилий. Он должен рисовать закругленные углы, метки и управляющие пиктограммы. Возможно, вы сможете добавить какое-нибудь фиктивное содержание, например изображение. На самом деле с этим изображением ничего не надо делать. Допускается (и даже рекомендуется), чтобы оно появилось в объекте класса
Simple_window
.

11. Определите класс

Binary_tree
, производный от класса
Shape
. Введите параметр, задающий количество уровней (
levels==0
означает, что в дереве нет ни одного узла,
levels==1
означает, что в дереве есть один узел,
levels==2
означает, что дерево состоит из вершины и двух узлов,
levels==3
означает, что дерево состоит из вершины и двух дочерних узлов, которые в свою очередь имеют по два дочерних узла, и т.д.). Пусть узел изображается маленьким кружочком. Соедините узлы линиями (как это принято). P.S. В компьютерных науках деревья изображаются растущими вниз от вершины (забавно, но нелогично, что ее часто называют корнем).

12. Модифицируйте класс

Binary_tree
так, чтобы он рисовал свои узлы с помощью виртуальной функции. Затем выведите из класса
Binary_tree
новый класс, в котором эта виртуальная функция замещается так, что узлы изображаются иначе (например, в виде треугольников).

13. Модифицируйте класс

Binary_tree
так, чтобы он имел параметр (или параметры, указывающие, какой вид линии используется для соединения узлов (например, стрелка, направленная вниз, или красная стрелка, направленная вверх). Заметьте, как в этом и последнем упражнениях используются два альтернативных способа, позволяющих сделать иерархию классов более гибкой и полезной.

14. Добавьте в класс

Binary_tree
операцию, добавляющую к узлу текст. Для того чтобы сделать это элегантно, можете модифицировать проект класса
Binary_tree
. Выберите способ идентификации узла; например, для перехода налево, направо, направо, налево и направо вниз по бинарному дереву можете использовать строку "
lrrlr
" (корневой узел может соответствовать как переходу влево, так и вправо).

15. Большинство иерархий классов не связано с графикой. Определите класс

Iterator
, содержащий чисто виртуальную функцию
next
, возвращающую указатель типа
double*
(см. главу 17). Теперь выведите из класса
Iterator
классы
Vector_iterator
и
List_iterator
так, чтобы функция
next
для класса
Vector_iterator
возвращала указатель на следующий элемент вектора типа
vector<double>
, а для класса
List_iterator
делала то же самое для списка типа
list<double>
. Инициализируйте объект класса
Vector_iterator
вектором
vector<double>
и сначала вызовите функцию
next
, возвращающую указатель на первый элемент, если он существует. Если такого элемента нет, верните нуль. Проверьте этот класс с помощью функции
void print(Iterator&)
, выводящей на печать элементы вектора типа
vector<double>
и списка типа
list<double>
.

16. Определите класс

Controller
, содержащий четыре виртуальные функции:
on
,
off
,
set_level(int)
и
show
. Выведите из класса
Controller
как минимум два класса. Один из них должен быть простым тестовым классом, в котором функция
show
выводит на печать информацию, включен или выключен контроллер, а также текущий уровень. Второй производный класс должен управлять цветом объекта класса
Shape
; точный смысл понятия “уровень” определите сами. Попробуйте найти третий объект для управления с помощью класса
Controller
.

17. Исключения, определенные в стандартной библиотеке языка C++, такие как

exception
,
runtime_error
и
out_of_range
(см. раздел 5.6.3), организованы в виде иерархии классов (с полезной виртуальной функцией
what
, возвращающей строку, которая предположительно содержит объяснение ошибки). Найдите источники информации об иерархии стандартных исключений в языке C++ и нарисуйте диаграмму этой иерархии классов.

Послесловие

Идеалом программирования вовсе не является создание одной программы, которая делает все. Цель программирования — создание множества классов, точно отражающих понятия, работающих вместе и позволяющих нам элегантно создавать приложения, затрачивая минимум усилий (по сравнению со сложностью задачи) при адекватной производительности и уверенности в правильности результатов. Такие программы понятны и удобны в сопровождении, т.е. их коды можно просто объединить, чтобы как можно быстрее выполнить поставленное задание. Классы, инкапсуляция (поддерживаемая разделами
private
и
protected
), наследование (поддерживаемое механизмом вывода классов), а также динамический полиморфизм (поддерживаемый виртуальными функциями) являются одними из наиболее мощных средств структурирования систем.

Глава 15

Графические функции и данные

“Лучшее — враг хорошего”.

Вольтер (Voltaire)

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

15.1. Введение

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

Поделиться с друзьями: