Естественно, сначала вектор points
Shape
полным функциональным интерфейсом, а не предоставлять функциям-членам классов, производных от класса Shape
, прямого доступа к его данным-членам. Одним людям создание функционального интерфейса кажется глупым, поскольку они считают, что недопустимо делать какие-либо данные-члены класса открытыми. Другим наш подход кажется слишком узким, потому что мы не разрешаем членам производных классов прямой доступ к членам базового класса.Классы, производные от класса Shape
Circle
и Polygon
, “понимают”, что означают их точки. Базовый класс Shape
этого “не понимает”, он просто хранит точки. Следовательно, производные классы должны иметь контроль над тем, как добавляются точки. Рассмотрим пример.• Классы Circle
Rectangle
не позволяют пользователю добавлять точки, они просто “не видят” в этом смысла. Что такое прямоугольник с дополнительной точкой? (См. раздел 12.7.6.)• Класс Lines
• Классы 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
fl_line(point(i–1).x,point(i–1).y,point(i).x,point(i).y);
}
number_of_points()
points.size()
.Решения, касающиеся управления доступом, очень важны. Теперь мы могли бы создать почти минимальную версию класса Shape
struct Shape { // слишком простое определение — не используется
Shape();
void draw() const; // работает с цветом и вызывает функцию
// draw_lines
virtual void draw_lines() const; // рисует линии
virtual void move(int dx, int dy); // перемещает фигуры +=dx
// и +=dy
vector
Color lcolor;
Line_style ls;
Color fcolor;
}