Circle
Ellipse
? С геометрической точки зрения каждая окружность является эллипсом, но не каждый эллипс является окружностью. В частности, окружность — это эллипс, у которого оба фокуса совпадают. Представьте себе, что мы определили класс Circle
как разновидность класса Ellipse
. В этом случае нам пришлось включать в представление дополнительные величины (окружность определяется центром и радиусом; для определения эллипса необходимы центр и пара осей). Мы не приветствуем излишние затраты памяти там, где они не нужны, но основная причина, по которой класс Circle
не сделан наследником класса Ellipse
, заключается в том, что мы не можем определить его, не заблокировав каким-то образом функции set_major()
и set_minor()
. Кроме того, фигура не была бы окружностью (что легко распознают математики), если бы мы использовали функцию set_major()
, чтобы обеспечить выполнение условия major()!=minor()
, — по крайней мере, после этого фигура перестанет быть окружностью. Нам не нужен объект, который иногда относится к одному типу (когда major()!=minor()
), а иногда к другому (когда major()==minor()
). Нам нужен объект (класса Ellipse
), который иногда выглядит как окружность. С другой стороны, объект класса Circle
никогда не превратится в эллипс с двумя неравными осями.
13.14. Класс Marked_polyline
Часто возникает необходимость пометить точки графика. График можно изобразить в виде ломаной, поэтому нам нужна ломаная, точки которой имели бы метки. Для этого предназначен класс Marked_polyline
Marked_polyline mpl("1234");
mpl.add(Point(100,100));
mpl.add(Point(150,200));
mpl.add(Point(250,250));
mpl.add(Point(300,200));
В результате выполнения этого фрагмента программы получим следующий результат:
Определение класса Marked_polyline
struct Marked_polyline:Open_polyline {
Marked_polyline(const string& m):mark(m)
{
if (m=="") mark = "*";
}
void draw_lines() const;
private:
string mark;
};
Поскольку этот класс является наследником класса Open_polyline
Point
, и все что нам для этого необходимо — иметь возможность ставить метки. В частности, функция draw_lines()
примет следующий вид:void Marked_polyline::draw_lines() const
{
Open_polyline::draw_lines();
for (int i=0; i
draw_mark(point(i),mark[i%mark.size()]);
}
Вызов функции Open_polyline::draw_lines()
mark[i%mark.size()]
выбирает символ, который должен быть использован следующим, циклически перебирая символы, хранящиеся в объекте класса Marked_polyline
. Оператор %
означает деление по модулю (взятие остатка). Для вывода буквы в заданной точке функция draw_lines()
использует вспомогательную функцию меньшего размера draw_mark()
.void draw_mark(Point xy, char c)
{
static const int dx = 4;
static const int dy = 4;
string m(1,c);
fl_draw(m.c_str(),xy.x–dx,xy.y+dy);
}
Константы dx
dy
используются для центрирования буквы относительно заданной точки. Объект m
класса хранит единственный символ c
. 13.15. Класс Marks
Иногда необходимо вывести метки отдельно от линий. Для этого предназначен класс Marks
Marks pp("x");
pp.add(Point(100,100));
pp.add(Point(150,200));
pp.add(Point(250,250));
pp.add(Point(300,200));