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

ЖАНРЫ

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

horizontal.set_color(Color::red);

vertical.set_color(Color::green);

На экране откроется окно, приведенное ниже.

13.6. Класс Open_polyline

Класс

Open_polyline
определяет фигуру, состоящую из ряда отрезков линий, соединенных между собой и заданных последовательностью точек. Слово
poly
имеет греческое происхождение и означает “много”, а
polyline
— это удобное
имя для фигуры, состоящей из многих линий. Рассмотрим пример.

Open_polyline opl;

opl.add(Point(100,100));

opl.add(Point(150,200));

opl.add(Point(250,250));

opl.add(Point(300,200));

Этот фрагмент кода создает фигуру, которую можно нарисовать, соединяя следующие точки.

В принципе

Open_polyline
— это выдуманное слово, которое мы позаимствовали из детской игры “Connect the Dots” (“Соедини точки”).

Класс

Open_polyline
определен следующим образом:

struct Open_polyline:Shape { // открытая последовательность линий

void add(Point p) { Shape::add(p); }

};

Да-да, это все определение. В нем практически ничего нет, кроме указания имени класса и того факта, что он является наследником класса

Shape
. Функция
add
класса
Open_polyline
просто позволяет пользователям получить доступ к функции
add
из класса
Shape
(т.е.
Shape::add
). Нам даже не нужно определять функцию
draw_lines
, так как класс
Shape
по умолчанию интерпретирует добавленные точки как последовательность линий, соединенных друг с другом.

13.7. Класс Closed_polyline

Класс

Closed_polyline
похож на класс
Open_polyline
, за исключением того, что последняя точка соединяется с первой. Например, можно было бы создать объект класса
Closed_polyline
из тех же точек, из которых был построен объект класса
Open_polyline
в разделе 13.6.

Closed_polyline cpl;

cpl.add(Point(100,100));

cpl.add(Point(150,200));

cpl.add(Point(250,250));

cpl.add(Point(300,200));

Как и ожидалось, результат идентичен тому, что мы получили в разделе 13.6, за исключением последнего отрезка.

Определение класса

Closed_polyline
приведено ниже.

struct Closed_polyline:Open_polyline { // замкнутый ряд линий

void draw_lines const;

};

void Closed_polyline::draw_lines const

{

Open_polyline::draw_lines; // сначала рисуем открытый ряд линий,

// затем рисуем замыкающую линию:

if (color.visibility)

fl_line(point(number_of_points–1).x,

point(number_of_points–1).y,

point(0).x,

point(0).y);

}

В классе

Closed_polyline
нужна отдельная функция
draw_lines
,
рисующая замыкающую линию, которая соединяет последнюю точку с первой. К счастью, для этого достаточно реализовать небольшую деталь, которая отличает класс
Closed_polyline
от класса
Shape
. Этот важный прием иногда называют “программированием различий“ (“programming by difference”). Нам нужно запрограммировать лишь то, что отличает наш производный класс (
Closed_polyline
) от базового (
Open_polyline
).

Итак, как же нарисовать замыкающую линию? Воспользуемся функцией

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

13.8. Класс Polygon

Класс Polygon очень похож на класс

Closed_polyline
. Единственная разница состоит в том, что в классе
Polygon
линии не могут пересекаться. Например, объект класса
Closed_polyline
, изображенный выше, был многоугольником, но если к нему добавить еще одну точку, то ситуация изменится.

cpl.add(Point(100,250));

Результат изображен ниже.

В соответствии с классическими определениями объект класса

Closed_polyline
многоугольником не является. Как определить класс
Polygon
так, чтобы он правильно отображал связь с классом
Closed_polyline
, не нарушая правил геометрии? Подсказка содержится в предыдущем описании. Класс
Polygon
— это класс
Closed_polyline
, в котором линии не пересекаются. Иначе говоря, мы могли бы подчеркнуть способ образования фигуры из точек и сказать, что класс
Polygon
— это класс
Closed_polyline
, в который невозможно добавить объект класса
Point
, определяющий отрезок линии, пересекающийся с одной из существующих линий в объекте класса
Polygon
.

Эта идея позволяет описать класс

Polygon
следующим образом:

struct Polygon:Closed_polyline { // замкнутая последовательность

// непересекающихся линий

void add(Point p);

void draw_lines const;

};

void Polygon::add(Point p)

{

// проверка того, что новая линия не пересекает существующие

// (код скрыт)

Closed_polyline::add(p);

}

Здесь мы унаследовали определение функции

draw_lines
из класса
Closed_polyline
, сэкономив усилия и избежав дублирования кода. К сожалению, мы должны проверить каждый вызов функции
add
. Это приводит нас к неэффективному алгоритму, сложность которого оценивается как N в квадрате, — определение объекта класса
Polygon
, состоящего из N точек, требует N*(N–1)/2 вызовов функции
intersect
. По существу, мы сделали предположение, что класс
Polygon
будет использоваться для создания многоугольников с меньшим количеством точек.

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