Читаем Программирование полностью

  Почему класс 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));


Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже