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

на главную - закладки

Жанры

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

// по умолчанию)

}

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

Обратите внимание на то, что функция
Shape::draw
не работает с цветом заливки фигуры и не управляет видимостью линий. Эти свойства обрабатывают отдельные функции
draw_lines
, которые лучше “знают”, как их интерпретировать. В принципе всю обработку цвета и стиля можно было бы перепоручить отдельным функциям
draw_lines
, но для этого пришлось бы повторять много одних и тех же фрагментов кода.

Рассмотрим теперь, как организовать работу с функцией

draw_lines
. Если немного подумать, то можно прийти к выводу, что функции-члену класса
Shape
было бы трудно рисовать все, что необходимо для создания любой разновидности фигуры. Для этого пришлось бы хранить в объекте класса Shape каждый пиксель каждой фигуры. Если мы используем вектор
vector<Point>
, то вынуждены хранить огромное количество точек. И что еще хуже, экран (т.е. устройство для вывода графических изображений) лучше “знает”, как это делать.

Для того чтобы избежать лишней работы и сохранять лишнюю информацию, примем другой подход: дадим каждому классу, производному от класса
Shape
, возможность самому определить, что он будет рисовать. Классы
Text
,
Rectangle
и
Circle
лучше “знают”, как нарисовать свои объекты. На самом деле все такие классы это “знают”. Помимо всего прочего, такие классы точно “знают” внутреннее представление информации. Например, объект класса
Circle
определяется точкой и радиусом, а не, скажем, отрезком линии. Генерирование требуемых битов для объекта класса
Circle
на основе точки и радиуса там, где это необходимо, и тогда, когда это необходимо, не слишком сложная и затратная работа. По этой причине в классе
Circle
определяется своя собственная функция
draw_lines
, которую мы хотим вызывать, а не функция
draw_lines
из класса
Shape
. Именно это означает слово
virtual
в объявлении функции
Shape::draw_lines
.

struct Shape {

// ...

virtual void draw_lines const;

// пусть каждый производный класс

// сам определяет свою собственную функцию draw_lines,

// если это необходимо

// ...

};

struct Circle : Shape {

// ...

void draw_lines const; // " замещение " функции

// Shape::draw_lines

// ...

};

Итак, функция

draw_lines
из класса
Shape
должна как-то вызывать одну из функций-членов класса
Circle
, если фигурой является объект класса
Shape
, и одну из функций-членов класса
Rectangle
, если фигура является объектом класса
Rectangle
. Вот что означает слово
virtual
в объявлении функции
draw_lines
:
если класс является производным от класса
Shape
, то он должен самостоятельно объявить свою собственную функцию
draw_lines
(с таким же именем, как функция
draw_lines
в классе
Shape
), которая будет вызвана вместо функции
draw_lines
из класса. В главе 13 показано, как это сделано в классах
Text
,
Circle
,
Closed_polyline
и т.д. Определение функции в производном классе, используемой с помощью интерфейса базового класса, называют замещением (overriding).

Обратите внимание на то, что, несмотря на свою главную роль в классе

Shape
, функция
draw_lines
находится в разделе
protected
. Это сделано не для того, чтобы подчеркнуть, что она предназначена для вызова “общим пользователем” — для этого есть функция
draw
. Просто тем самым мы указали, что функция
draw_lines
— это “деталь реализации”, используемая функцией
draw
и классами, производными от класса
Shape
.

На этом завершается описание нашей графической модели, начатое в разделе 12.2. Система, управляющая экраном, “знает” о классе

Window
. Класс
Window
“знает” о классе
Shape
и может вызывать его функцию-член
draw
. В заключение функция
draw
вызывает функцию
draw_lines
, чтобы нарисовать конкретную фигуру. Вызов функции
gui_main
в нашем пользовательском коде запускает драйвер экрана.

Что делает функция

gui_main
? До сих пор мы не видели ее в нашей программе. Вместо нее мы использовали функцию
wait_for_button
, которая вызывала драйвер экрана более простым способом.

Функция

move
класса
Shape
просто перемещает каждую хранимую точку на определенное расстояние относительно текущей позиции.

void Shape::move(int dx, int dy) // перемещает фигуру +=dx and +=dy

{

for (int i = 0; i<points.size; ++i) {

points[i].x+=dx;

points[i].y+=dy;

}

}

Подобно функции

draw_lines
, функция
move
является виртуальной, поскольку производный класс может иметь данные, которые необходимо переместить и о которых может “не знать” класс
Shape
. В качестве примера можно привести класс
Axis
(см. разделы 12.7.3 и 15.4).

Функция

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

14.2.4. Копирование и изменчивость

Класс Shape содержит закрытые объявления копирующего конструктора (copy constructor) и оператора копирующего присваивания (copy assignment constructor).

Поделиться:
Популярные книги

Возвышение Меркурия. Книга 2

Кронос Александр
2. Меркурий
Фантастика:
фэнтези
5.00
рейтинг книги
Возвышение Меркурия. Книга 2

Безымянный раб

Зыков Виталий Валерьевич
1. Дорога домой
Фантастика:
фэнтези
9.31
рейтинг книги
Безымянный раб

Волк 4: Лихие 90-е

Киров Никита
4. Волков
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Волк 4: Лихие 90-е

Кремлевские звезды

Ромов Дмитрий
6. Цеховик
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Кремлевские звезды

Газлайтер. Том 4

Володин Григорий
4. История Телепата
Фантастика:
попаданцы
альтернативная история
аниме
5.00
рейтинг книги
Газлайтер. Том 4

Восход. Солнцев. Книга VIII

Скабер Артемий
8. Голос Бога
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Восход. Солнцев. Книга VIII

Кровь и Пламя

Михайлов Дем Алексеевич
7. Изгой
Фантастика:
фэнтези
8.95
рейтинг книги
Кровь и Пламя

Объединитель

Астахов Евгений Евгеньевич
8. Сопряжение
Фантастика:
боевая фантастика
постапокалипсис
рпг
5.00
рейтинг книги
Объединитель

Комбинация

Ланцов Михаил Алексеевич
2. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Комбинация

На границе империй. Том 7. Часть 2

INDIGO
8. Фортуна дама переменчивая
Фантастика:
космическая фантастика
попаданцы
6.13
рейтинг книги
На границе империй. Том 7. Часть 2

Дайте поспать!

Матисов Павел
1. Вечный Сон
Фантастика:
юмористическое фэнтези
постапокалипсис
рпг
5.00
рейтинг книги
Дайте поспать!

Бальмануг. Студентка

Лашина Полина
2. Мир Десяти
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Бальмануг. Студентка

Довлатов. Сонный лекарь

Голд Джон
1. Не вывожу
Фантастика:
альтернативная история
аниме
5.00
рейтинг книги
Довлатов. Сонный лекарь

Мастер Разума VII

Кронос Александр
7. Мастер Разума
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Мастер Разума VII