Вопрос 24: Пример программы с иерархией классов. Монитор экрана. Библиотека фигур. Возможная иерархия классов и её смысл.

В программе объявлен абстрактный класс «фигура» (shape). Все конкретные фигуры — линия, прямоугольник и т. п. — являются производными от этого класса. Класс «фигура» поддерживает действия, необходимые для всех фигур: он создаёт из всех объявляемых фигур общий список, который может быть обработан программой рисования при выдаче фигур на экран. Кроме того, в классе «фигура» объявлен набор функций-членов, которые должны поддерживать все фигуры, чтобы из них можно было создавать картинки. Это функции, возвращающие координаты всех крайних точек фигуры, по которым их можно будет стыковать. Эти функции — чисто виртуальные, они должны быть обязательно определены затем отдельно в каждой фигуре. Имеются также два дополнительных класса, уточняющие свойства фигур. Некоторые фигуры можно поворачивать. Для таких фигур имеется базовый класс rotatable, производный от shape. Для других фигур возможна операция отражения относительно горизонтальной или вертикальной оси. Эти фигуры можно строить на базе класса reflectable. Если фигура имеет оба этих свойства, то она должна быть производной от обоих классов.

const int XMAX=80; //Размер экрана
const int YMAX=40;

class point {    //Точка на экране
public:
  int x, y;

  point(int a = 0, int b = 0) : x(a), y(b){  }
};

// Набор утилит для работы с экраном
void put_point(int a, int b); // Вывод точки
void put_point(point p) {
    put_point(p.x, p.y);
}
void put_line(int, int, int, int); // Вывод линии
void put_line(point a, point b) {
    put_line(a.x, a.y, b.x, b.y);
}
extern void screen_init( );    // Создание экрана
extern void screen_destroy( );    // Удаление экрана
extern void screen_refresh( );    // Обновление
extern void screen_clear( );    // Очистка

// Поддержка экрана в форме матрицы символов ==
char screen[XMAX] [YMAX];    
enum color { black = '*', white = '.' };

void screen_init( )
{
  for (int y=0; y<YMAX; y++)
    for (int x=0; x<XMAX; x++)
       screen[x][y] = white;
}

int on_screen(int a, int b) // проверка попадания на экран
{ return 0 <= a && a < XMAX && 0 <= b && b < YMAX; }

void put_point(int a, int b)
{ if (on_screen(a,b)) screen[a] [b] = black; }

void put_line(int x0, int y0, int x1, int y1)
/*
Рисование отрезка прямой (x0,y0) - (x1,y1).
Уравнение прямой: b(x-x0) + a(y-y0) = 0.
Минимизируется величина abs(eps),
где eps = 2*(b(x-x0)) + a(y-y0).
*/
{
  int dx = 1;
  int a = x1 - x0;
  if (a < 0) dx = -1, a = -a;
  int dy = 1;
  int b = y1 - y0;
  if (b < 0) dy = -1, b = -b;
  int two_a = 2*a;
  int two_b = 2*b;
  int xcrit = -b + two_a;
  int eps = 0;

  for (;;) {
    put_point(x0, y0);
    if (x0 == x1 && y0 == y1) break;
    if (eps <= xcrit) x0 += dx, eps += two_b;
    if (eps >= a || a < b) y0 += dy, eps -= two_a;
  }
}

void screen_clear( ) { screen_init( ); } //Очистка экрана

void screen_refresh( ) // Обновление экрана
{
  for (int y = YMAX-1; 0 <= y; --y) { // с верхней строки до нижней
    for (int x = 0; x < XMAX; ++x)    // от левого столбца до правого
      cout << screen[x] [y];
    cout << '\n';
  }
}

//Библиотека фигур
struct shape { // (Абстрактный)Виртуальный базовый класс "фигура"
  static shape* list;
  shape* next;
  shape( ) { next = list; list = this; }
  virtual point north( ) const = 0;
  virtual point south( ) const = 0;
  virtual point east( ) const = 0;
  virtual point west( ) const = 0;
  virtual point neast( ) const = 0;
  virtual point seast( ) const = 0;
  virtual point nwest( ) const = 0;
  virtual point swest( ) const = 0;
  virtual void draw( ) = 0;
  virtual void move(int, int) = 0;
};

shape * shape :: list = nullptr;    //Инициализация списка фигур

class rotatable : public shape { //Фигуры, пригодные к повороту 
public:
    virtual void rotate_left( ) = 0;    //Повернуть влево
    virtual void rotate_right( ) = 0;    //Повернуть вправо
};

class reflectable : public shape { // Фигуры, пригодные
                   // к зеркальному отражению
public:
    virtual void flip_horisontally( ) = 0;    // Отразить горизонтально
    virtual void flip_vertically( ) = 0;    // Отразить вертикально
};

class line : public shape {
/* отрезок прямой ["w", "e" ].
north( ) определяет точку "выше центра отрезка и так далеко
на север, как самая его северная точка", и т. п. */
public:
  point w, e;

  line(point a, point b) : w(a), e(b) { };
  line(point a, int L) : w(point(a.x + L - 1, a.y)), e(a) {  };
  point north( ) const { return point((w.x+e.x)/2, e.y<w.y? w.y : e.y); }
  point south( ) const { return point((w.x+e.x)/2, e.y<w.y? e.y : w.y); }
  point east( ) const { return point((w.x+e.x)/2, e.y<w.y? e.y : w.y); }
  point west( ) const { return point((w.x+e.x)/2, e.y<w.y? e.y : w.y); }
  point neast( ) const { return point((w.x+e.x)/2, e.y<w.y? e.y : w.y); }
  point seast( ) const { return point((w.x+e.x)/2, e.y<w.y? e.y : w.y); }
  point nwest( ) const { return point((w.x+e.x)/2, e.y<w.y? e.y : w.y); }
  point swest( ) const { return point((w.x+e.x)/2, e.y<w.y? e.y : w.y); }
  void move(int a, int b) { w.x += a; w.y += b; e.x += a; e.y += b; }
  void draw( ) { put_line(w, e); }
};

// Прямоугольник
class rectangle : public rotatable {
/* nw ------ n ------ ne
   |               |
   |               |
   w         c          e
   |               |
   |               |
   sw ------ s ------ se */
  point sw, ne;
public:
  rectangle(point, point);
  point north( ) const { return point((sw.x + ne.x) / 2, ne.y); }
  point south( ) const { return point((sw.x + ne.x) / 2, sw.y); }
  point east( ) const { return point(sw.x, (sw.y + ne.y) / 2); }
  point west( ) const { return point(ne.x, (sw.y + ne.y) / 2); }
  point neast( ) const { return ne; }
  point seast( ) const { return point(sw.x, ne.y); }
  point nwest( ) const { return point(ne.x, sw.y); }
  point swest( ) const { return sw; }

  void rotate_right() // Поворот вправо относительно se
  { 
      int w = ne.x - sw.x, h = ne.y - sw.y; 
      sw.x = ne.x – h * 2; ne.y = sw.y + w / 2;
  }
  void rotate_left() //Поворот влево относительно sw
  {
      int w = ne.x - sw.x, h = ne.y - sw.y; 
      ne.x = sw.x + h * 2; ne.y = sw.y + w / 2;
  }
  void move(int a, int b)
  {
      sw.x += a; sw.y += b; ne.x += a; ne.y += b;
  }
  void draw( );
};

rectangle::rectangle(point a, point b)
{ if (a.x <= b.x) {
      if (a.y <= b.y) sw = a, ne = b;
      else sw = point(a.x, b.y), ne = point(b.x, a.y);
  }
  else {
      if (a.y <= b.y) sw = point(b.x, a.y), ne = point(a.x, b.y);
      else sw = b, ne = a;
    }
}

void rectangle::draw( )
{
    point nw(sw.x, ne.y);
    point se(ne.x, sw.y);
    put_line(nw, ne);
    put_line(ne, se);
    put_line(se, sw);
    put_line(sw, nw);
}

void shape_refresh( ) // Перерисовка всех фигур
{
  screen_clear( );
  for (shape* p = shape :: list; p; p = p->next) p->draw( );
  screen_refresh( );
}

void up(shape* p, const shape* q) // поместить p над q
{
  point n = q->north( );
  point s = p->south( );
  p->move(n.x - s.x, n.y - s.y + 1);
}

//========================================================
// Прикладная программа: 
// пополнение и использование библиотеки фигур
#include "stdafx.h"
#include <conio.h>
#include <iostream>
#include "screen.h"
#include "shape.h"

// Дополнительная "сборная" фигура
class myshape : public rectangle {
  line* l_eye; // левый глаз
  line* r_eye; // правый глаз
  line* mouth; // рот
public:
  myshape(point, point);
  void draw( );
  void move(int, int);
};

myshape::myshape(point a, point b) : rectangle(a, b)
{
    int ll = neast( ).x - swest( ).x + 1;
    int hh = neast( ).y - swest( ).y + 1;
    l_eye = new line(point(swest( ).x + 2, swest( ).y + hh * 3 / 4), 2);
    r_eye = new line(point(swest( ).x + ll - 4, swest( ).y + hh * 3 / 4), 2);
    mouth = new line(point(swest( ).x + 2, swest( ).y + hh / 4), ll - 4);
}

void myshape::draw( )
{
    rectangle :: draw( );
    int a = (swest( ).x + neast( ).x) / 2;
    int b = (swest( ).y + neast( ).y) / 2;
    put_point(point(a, b));
}

void myshape :: move(int a, int b)
{
    rectangle :: move(a, b);
    l_eye->move(a, b);
    r_eye->move(a, b);
    mouth->move(a, b);
}

int _tmain( )
{
    screen_init( );
//== 1.Объявление набора фигур ==
    rotatable* p1 = new rectangle(point(0, 0), point(14, 5));
    shape* p2 = new line(point(0,15),17);
    shape* p3 = new myshape(point(15,10), point(27,18));
    shape_refresh( );
    _getch( );
//== 2.Ориентация ==
    p1->rotate_right( );
        shape_refresh( );
    _getch( );
//== 3.Сборка изображения ==
    p3->move(-10, -10);
    up(p2, p3);
    up(p1, p2);
    shape_refresh( );
    system(“pause”);
//    screen_destroy( );
    return 0;
}

При запуске программы на экран сначала выводится объявленная коллекция фигур. Затем демонстрируется результат поворота/отражения некоторых фигур как подготовка к их использованию. Далее фигуры перемещаются и образуют заданную картинку. Для рисования использованы прямоугольники, линии и точки. Физиономия является пользовательской фигурой.

results matching ""

    No results matching ""