void set_fill_color(Color col);
Color fill_color() const;
Point point(int i) const; // доступ к точкам только для чтения
int number_of_points() const;
virtual ~Shape() { }
protected:
Shape();
virtual void draw_lines() const; // рисует линии
void add(Point p); // добавляет объект p к точкам
void set_point(int i, Point p); // points[i]=p;
private:
vector<Point> points; // не используется всеми фигурами
Color lcolor; // цвет для линий и символов
Line_style ls;
Color fcolor; // заполняет цветом
Shape(const Shape&); // копирующий конструктор
Shape& operator=(const Shape&);
};
Это относительно сложный класс, разработанный для поддержки работы множества графических классов и представления общего понятия о фигуре на экране. Однако в нем всего четыре данных-членов и пятнадцать функций. Более того, эти функции почти все тривиальны, так что мы можем сосредоточиться на вопросах проектирования. В оставшейся части главы мы пройдемся по всем членам шаг за шагом и объясним их роль в классе.
14.2.1. Абстрактный класс
Сначала рассмотрим конструктор класса
Shape
:
protected:
Shape();
который находится в разделе
protected
. Это значит, что его можно непосредственно использовать только в классах, производных от класса
Shape
(используя обозначение
:Shape
). Иначе говоря, класс
Shape
можно использовать только в качестве базы для других классов, таких как
Line
и
Open_polyline
. Цель ключевого слова
protected:
— гарантировать, что мы не сможем создать объекты класса
Shape
непосредственно.
Рассмотрим пример.
Shape ss; // ошибка: невозможно создать объект класса Shape
Класс
Shape
может быть использован только в роли базового класса. В данном случае ничего страшного не произошло бы, если бы мы позволили создавать объекты класса
Shape
непосредственно, но, ограничив его применение, мы открыли возможность его модификации, что было бы невозможно, если бы кто-то мог его использовать непосредственно. Кроме того, запретив прямое создание объектов класса
Shape
, мы непосредственно моделируем идею о том, что абстрактной фигуры в природе не существует, а реальными являются лишь конкретные фигуры, такие как объекты класса
Circle
и
Closed_polyline
. Подумайте об этом! Как выглядит абстрактная фигура? Единственный разумный ответ на такой вопрос — встречный вопрос: какая фигура? Понятие о фигуре, воплощенное в классе
Shape
, носит абстрактный характер. Это важное и часто полезное свойство, поэтому мы не хотим компрометировать его в нашей программе. Позволить пользователям непосредственно создавать объекты класса Shape противоречило бы нашим представлениям о классах как о прямых воплощениях понятий. Конструктор определяется следующим образом:
Shape::Shape()
:lcolor(fl_color()), // цвет линий и символов по умолчанию
ls(0), // стиль по умолчанию
fcolor(Color::invisible) // без заполнения
{
}
Это конструктор по умолчанию, поэтому все его члены также задаются по умолчанию. Здесь снова в качестве основы использована библиотека FLTK. Однако понятия цвета и стиля, принятые в библиотеке FLTK, прямо не упоминаются. Они являются частью реализации классов
Shape
,
Color
и
Line_style
.
Объект класса
vector<Points>
по умолчанию считается пустым вектором.
Класс является
абстрактным (abstract), если его можно использовать только в качестве базового класса. Для того чтобы класс стал абстрактным, в нем часто объявляют
чисто виртуальную функцию (pure virtual function), которую мы рассмотрим в разделе 14.3.5. Класс, который можно использовать для создания объектов, т.е. не абстрактный класс, называется
конкретным (concrete). Обратите внимание на то, что слова
абстрактный и
конкретный часто используются и в быту. Представим себе, что мы идем в магазин покупать фотоаппарат. Однако мы не можем просто попросить какой-то фотоаппарат и принести его домой. Какую торговую марку вы предпочитаете? Какую модель фотоаппарата хотите купить? Слово
фотоаппарат — это обобщение; оно ссылается на абстрактное понятие. Название “Olympus E-3” означает конкретную разновидность фотоаппарата, конкретный экземпляр которого с уникальным серийным номером мы можем купить (в обмен на большую сумму денег). Итак, фотоаппарат — это абстрактный (базовый) класс, “Olimpus E-3” — конкретный (производный) класс, а реальный фотоаппарат в моей руке (если я его купил) — это объект.
Объявление
virtual ~Shape() { }
определяет виртуальный деструктор. Мы не будем пока его использовать и рассмотрим позднее, в разделе 17.5.2.
14.2.2. Управление доступом
Класс
Shape
объявляет все данные-члены закрытыми.
private:
vector<Point> points;
Color lcolor;
Line_style ls;
Color fcolor;
Поскольку данные-члены класса
Shape
объявлены закрытыми, нам нужно предусмотреть функции доступа. Существует несколько стилей решения этой задачи. Мы выбрали простой, удобный и понятный. Если у нас есть член, представляющий свойство
X
, то мы предусмотрели пару функций,
X()
и
set_X()
, для чтения и записи соответственно. Рассмотрим пример.