Шрифт:
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);
}
Естественно, сначала вектор
points
пуст. Мы решили снабдить класс Shape
полным функциональным интерфейсом, а не предоставлять функциям-членам классов, производных от класса Shape
, прямого доступа к его данным-членам. Одним людям создание функционального интерфейса кажется глупым, поскольку они считают, что недопустимо делать какие-либо данные-члены класса открытыми. Другим наш подход кажется слишком узким, потому что мы не разрешаем членам производных классов прямой доступ к членам базового класса. Классы, производные от класса
Shape
, например Circle
и Polygon
, “понимают”, что означают их точки. Базовый класс Shape
этого “не понимает”, он просто хранит точки. Следовательно, производные классы должны иметь контроль над тем, как добавляются точки. Рассмотрим пример. • Классы
Circle
и Rectangle
не позволяют пользователю добавлять точки, они просто “не видят” в этом смысла. Что такое прямоугольник с дополнительной точкой? (См. раздел 12.7.6.) • Класс
Lines
позволяет добавлять любые пары точек (но не отдельные точки; см. раздел 13.3). • Классы
Open_polyline
и Marks
позволяют добавлять любое количество точек. • Класс
Polygon
позволяет добавлять точки только с помощью функции add
, проверяющей пересечения (раздел 13.8).
add
в раздел protected
(т.е. сделали ее доступной только для производных классов), чтобы гарантировать, что производные классы смогут управлять добавлением точек. Если бы функция add
находилась в разделе public
(т.е. каждый класс мог добавлять точки) или private
(только класс Shape
мог добавлять точки), то такое точное соответствие функциональных возможностей нашему представлению о фигуре стало бы невозможным. По аналогичным причинам мы поместили функцию
set_point
в класс protected
. В общем, только производный класс может “знать”, что означают точки и можно ли их изменять, не нарушая инвариант. Например, если класс
Regular_hexagon
объявлен как множество, состоящее из шести точек, то изменение даже одной точки может породить фигуру, не являющуюся правильным шестиугольником. С другой стороны, если мы изменим одну из точек прямоугольника, то в результате все равно получим прямоугольник. Фактически функция set_point
в этом случае оказывается ненужной, поэтому мы включили ее просто для того, чтобы обеспечить выполнение правил чтения и записи каждого атрибута класса Shape
. Например, если бы мы захотели создать класс Mutable_rectangle
, то могли бы вывести его из класса Rectangle
и снабдить операциями, изменяющими точки. Мы поместили вектор
points
объектов класса Point
в раздел private
, чтобы защитить его от нежелательных изменений. Для того чтобы он был полезным, мы должны обеспечить доступ к нему.
void Shape::set_point(int i, Point p) // не используется
{
points[i] = p;
}
Point Shape::point(int i) const
{
return points[i];
}
int Shape::number_of_points const
{
return points.size;
}
В производном классе эти функции используются так:
void Lines::draw_lines const
// рисует линии, соединяющие пары точек
{
for (int i=1; i<number_of_points; i+=2)
fl_line(point(i–1).x,point(i–1).y,point(i).x,point(i).y);