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 по умолчанию считается пустым вектором.
Объявление
virtual ~Shape() { }
определяет виртуальный деструктор. Мы не будем пока его использовать и рассмотрим позднее, в разделе 17.5.2.
14.2.2. Управление доступом
Класс Shape объявляет все данные-члены закрытыми.
private:
vector
Color lcolor;
Line_style ls;
Color fcolor;
Shape объявлены закрытыми, нам нужно предусмотреть функции доступа. Существует несколько стилей решения этой задачи. Мы выбрали простой, удобный и понятный. Если у нас есть член, представляющий свойство X, то мы предусмотрели пару функций, X() и set_X(), для чтения и записи соответственно. Рассмотрим пример.
void Shape::set_color(Color col)
{
lcolor = col;
}
Color Shape::color() const
{
return lcolor;
}
Основной недостаток этого стиля заключается в том, что мы не можем назвать переменную так же, как функцию для ее чтения. Как всегда, мы предпочли выбрать наиболее удобные имена для функций, поскольку они являются частью открытого интерфейса. Как назвать закрытые переменные, менее важно. Обратите внимание на то, что мы использовали ключевое слово const, чтобы подчеркнуть, что функция чтения не может модифицировать члены своего класса Shape (см. раздел 9.7.4).
В классе Shape хранится вектор объектов класса Point с именем points, которые предназначены для его производных классов. Для добавления объектов класса Point в вектор points предусмотрена функция add().
void Shape::add(Point p) // защищенный
{
points.push_back(p);
}