Читать интересную книгу Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 134 135 136 137 138 139 140 141 142 ... 337
в разделах 12.7.7 и 12.7.8), очень полезны строковые потоки (см. раздел 11.4).

struct Text:Shape {

  // точка в левом нижнем углу первой буквы

  Text(Point x, const string& s)

    :lab(s), fnt(fl_font()), fnt_sz(fl_size()) { add(x); }

  void draw_lines() const;

  void set_label(const string& s) { lab = s; }

  string label() const { return lab; }

  void set_font(Font f) { fnt = f; }

  Font font() const { return fnt; }

  void set_font_size(int s) { fnt_sz = s; }

  int font_size() const { return fnt_sz; }

private:

  string lab; // label

  Font fnt;

  int fnt_sz;

};

Класс Text имеет свою собственную функцию-член draw_lines(), поскольку только он знает, как хранится его строка.

void Text::draw_lines() const

{

  fl_draw(lab.c_str(),point(0).x,point(0).y);

}

Цвет символов определяется точно так же, как в фигурах, состоящих из линий (например, Open_polyline и Circle), поэтому можем выбирать новый цвет с помощью функции set_color(), а определять текущий цвет — с помощью функции color(). Размер и шрифт символов выбираются аналогично. В классе предусмотрено небольшое количество заранее определенных шрифтов.

class Font { // шрифт символа

public:

  enum Font_type {

    helvetica=FL_HELVETICA,

    helvetica_bold=FL_HELVETICA_BOLD,

    helvetica_italic=FL_HELVETICA_ITALIC,

    helvetica_bold_italic=FL_HELVETICA_BOLD_ITALIC,

    courier=FL_COURIER,

    courier_bold=FL_COURIER_BOLD,

    courier_italic=FL_COURIER_ITALIC,

    courier_bold_italic=FL_COURIER_BOLD_ITALIC,

    times=FL_TIMES,

    times_bold=FL_TIMES_BOLD,

    times_italic=FL_TIMES_ITALIC,

    times_bold_italic=FL_TIMES_BOLD_ITALIC,

    symbol=FL_SYMBOL,

    screen=FL_SCREEN,

    screen_bold=FL_SCREEN_BOLD,

    zapf_dingbats=FL_ZAPF_DINGBATS

  };

  Font(Font_type ff):f(ff) { }

  Font(int ff) :f(ff) { }

  int as_int() const { return f; }

private:

  int f;

};

Стиль определения класса Font совпадает со стилями определения классов Color (см. раздел 13.4) и Line_style (см. раздел 13.5). 

13.12. Класс Circle

 Просто для того чтобы показать, что не все фигуры в мире являются прямоугольными, мы создали классы Circle и Ellipse. Объект класса Circle определяется центром и радиусом.

struct Circle:Shape {

  Circle(Point p, int rr); // центр и радиус

  void draw_lines() const;

  Point center() const;

  int radius() const { return r; }

  void set_radius(int rr) { r=rr; }

private:

  int r;

};

Использовать класс Circle можно следующим образом:

Circle c1(Point(100,200),50);

Circle c2(Point(150,200),100);

Circle c3(Point(200,200),150);

Эти инструкции рисуют три окружности разных радиусов, центры которых лежат на горизонтальной линии.

Основной особенностью реализации класса Circle является то, что в нем хранится не центр, а левая верхняя точка угла квадрата, окаймляющего окружность. Можно было бы хранить и центр окружности, но мы выбрали вариант, позволяющий библиотеке FLTK оптимизировать процесс рисования окружности. Это еще один пример того, как с помощью класса можно создать другое (предположительно, более точное) представление понятия, для реализации которого он предназначен.

Circle::Circle(Point p, int rr) // центр и радиус

       :r(rr)

{

  add(Point(p.x–r,p.y–r));      // хранит левый верхний угол

}

Point Circle::center() const

{

  return Point(point(0).x+r, point(0).y+r);

}

void Circle::draw_lines() const

{

  if (color().visibility())

    fl_arc(point(0).x,point(0).y,r+r,r+r,0,360);

}

Обратите внимание на использование функции fl_arc(), рисующей окружность. Первые два аргумента задают левый верхний угол, вторые два — ширину и высоту наименьшего прямоугольника, окаймляющего окружность, а последние два аргумента задают начальный и последний углы. Для того чтобы нарисовать окружность, нужно обойти вокруг ее центра все 360 градусов, но с помощью функции fl_arc() можно нарисовать только часть окружности (и часть эллипса); см. упр. 1. 

13.13. Класс Ellipse

Эллипс похож на окружность, но он определяется большой и малой осями, а не радиусом. Иначе говоря, для того чтобы определить эллипс, мы должны задать координаты центра, а также расстояние от центра до точки на оси x и расстояние от центра до точки на оси y.

struct Ellipse:Shape {

  // центр, минимальное и максимальное расстояние от центра

  Ellipse(Point p, int w, int h);

  void draw_lines() const;

  Point center() const;

  Point focus1() const;

  Point focus2() const;

  void set_major(int ww) { w=ww; }

  int major() const { return w; }

  void set_minor(int hh) { h=hh; }

  int minor() const { return h; }

private:

  int w;

  int h;

};

Класс Ellipse можно использовать следующим образом:

Ellipse e1(Point(200,200),50,50);

Ellipse e2(Point(200,200),100,50);

Ellipse e3(Point(200,200),100,150);

Этот фрагмент программы рисует три эллипса с общим центром и разными осями.

Объект класса Ellipse, для которого выполняется условие major()==minor(), выглядит как окружность. Эллипс можно также задать с помощью двух фокусов и суммы расстояний от точки до фокусов. Имея объект класса Ellipse, можем вычислить фокус. Рассмотрим пример.

Point Ellipse::focus1() const

{

  return Point(center().x+sqrt(double(w*w–h*h)),center().y);

}

 

 Почему класс Circle не является наследником класса Ellipse? С геометрической точки зрения каждая окружность является эллипсом, но не каждый эллипс является окружностью. В частности, окружность — это эллипс, у которого оба фокуса совпадают. Представьте себе, что мы определили класс Circle как разновидность класса Ellipse. В этом случае нам пришлось включать в представление дополнительные величины (окружность определяется центром и радиусом; для определения эллипса необходимы центр и пара осей). Мы не приветствуем излишние затраты памяти там, где они не нужны, но основная причина, по которой класс Circle не сделан наследником класса Ellipse, заключается в том, что мы не можем определить его, не заблокировав каким-то образом функции set_major() и set_minor(). Кроме того, фигура не была бы окружностью (что легко распознают математики), если бы мы использовали функцию set_major(), чтобы обеспечить выполнение условия major()!=minor(), — по крайней мере, после
1 ... 134 135 136 137 138 139 140 141 142 ... 337
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп.
Книги, аналогичгные Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

Оставить комментарий