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

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
системе выбрать место в памяти:

  Window(int w, int h, const string& title);

  // верхний левый угол в точке xy:

  Window(Point xy, int w, int h, const string& title);

  virtual ~Window() { }

  int x_max() const { return w; }

  int y_max() const { return h; }

  void resize(int ww, int hh) { w=ww, h=hh; size(ww,hh); }

  void set_label(const string& s) { label(s.c_str()); }

  void attach(Shape& s) { shapes.push_back(&s); }

  void attach(Widget&);

  void detach(Shape& s);     // удаляет элемент w из фигур

  void detach(Widget& w);    // удаляет элемент w из окна

                             // (отключает обратные вызовы)

  void put_on_top(Shape& p); // помещает объект p поверх

                             // всех других фигур

protected:

  void draw();

private:

  vector<Shape*> shapes; // фигуры связываются с окном

  int w,h;               // размер окна

  void init();

};

Итак, когда мы связываем фигуру с окном, используя функцию attach(), мы храним указатель в объектах класса Shape, поэтому объект класса Window может рисовать соответствующую фигуру. Поскольку впоследствии мы можем отсоединить фигуру от окна с помощью функции detach(), поэтому нам нужен указатель. По существу, присоединенная фигура принадлежит своему коду; мы просто передаем объекту класса Window ссылку на нее. Функция Window::attach() преобразовывает свой аргумент в указатель, чтобы его можно было сохранить. Как показано выше, функция attach() является тривиальной; функция detach() немного сложнее. Открыв файл Window.cpp, мы видим следующее.

void Window::detach(Shape& s)

 // определяет, что первой должна быть удалена

 // последняя присоединенная фигура

{

  for (unsigned int i = shapes.size(); 0<i; ––i)

  if (shapes[i–1]==&s) shapes.erase(&shapes[i–1]);

}

Функция-член erase() удаляет (стирает) значение из вектора, уменьшая его размер на единицу (раздел 20.7.1). Класс Window используется как базовый, поэтому он содержит виртуальный деструктор (раздел 17.5.2).

Д.4. Реализация класса Vector_ref

По существу, класс Vector_ref имитирует вектор ссылок. Мы можем инициализировать его ссылками или указателями.

• Если объект передается объекту класса Vector_ref с помощью ссылки, то предполагается, что он принадлежит вызывающей функции, которая управляет его временем жизни (например, объект — это переменная, находящаяся в определенной области видимости).

• Если объект передается объекту класса Vector_ref с помощью указателя, то предполагается, что он размещен в памяти с помощью оператора new, а ответственность за его удаление несет класс Vector_ref.

Элемент хранится в объекте класса Vector_ref в виде указателя, а не как копия объекта, и имеет семантику ссылок. Например, можно поместить в вектор класса Vector_ref<Shape> объект класса Circle, не подвергаясь опасности срезки.

template<class T> class Vector_ref {

  vector<T*> v;

  vector<T*> owned;

public:

  Vector_ref() {}

  Vector_ref(T* a, T* b = 0, T* c = 0, T* d = 0);

  ~Vector_ref() { for (int i=0; i<owned.size(); ++i)

                  delete owned[i]; }

  void push_back(T& s) { v.push_back(&s); }

  void push_back(T* p) { v.push_back(p); owned.push_back(p); }

  T& operator[](int i) { return *v[i]; }

  const T& operator[](int i) const { return *v[i]; }

  int size() const { return v.size(); }

};

Деструктор класса Vector_ref удаляет каждый объект, переданный ему как указатель.

Д.5. Пример: манипулирование объектами класса Widget

Это законченная программа. Она демонстрирует многие из свойств классов Widget/Window. Мы поместили в нее минимальное количество комментариев. К сожалению, такое недостаточное комментирование программ — довольно распространенное явление. Попытайтесь выполнить эту программу и объяснить, как она работает.

#include "../GUI.h"

using namespace Graph_lib;

class W7 : public Window {

 // четыре способа продемонстрировать, что кнопка может

 // передвигаться:

 // показать/скрыть, изменить местоположение, создать новую

 // и присоединить/отсоединить

public:

  W7(int n, int n, const string& t); 

  Button* p1;       // показать/скрыть

  Button* p2;

  bool sh_left;

  Button* mvp;      // переместить

  bool mv_left;

  Button* cdp;      // создать/уничтожить

  bool cd_left;

  Button* adp1;     // активировать/деактивировать

  Button* adp2;

  bool ad_left;

  void sh();        // действия

  void mv();

  void cd();

  void ad();

  static void cb_sh(Address, Address addr) // обратные вызовы

    { reference_to<W7>(addr).sh(); }

  static void cb_mv(Address, Address addr)

    { reference_to<W7>(addr).mv(); }

  static void cb_cd(Address, Address addr)

    { reference_to<W7>(addr).cd(); }

  static void cb_ad(Address, Address addr)

    { reference_to<W7>(addr).ad(); }

};

Однако объект класса W7 (эксперимент с объектом класса Window номер 7) на самом деле содержит шесть кнопок: просто две из них он скрывает.

W7::W7(int w, int h, const string& t)

 :Window(w,h,t),

 sh_left(true),mv_left(true),cd_left(true),ad_left(true)

{

  p1 = new Button(Point(100,100),50,20,"show",cb_sh);

  p2 = new Button(Point(200,100),50,20,"hide",cb_sh);

  mvp = new Button(Point(100,200),50,20,"move",cb_mv);

  cdp = new Button(Point(100,300),50,20,"create",cb_cd);

  adp1 = new Button(Point(100,400),50,20,"activate",cb_ad);

  adp2 = new Button(Point(200,400),80,20,"deactivate",cb_ad);

  attach(*p1);

  attach(*p2);

  attach(*mvp);

  attach(*cdp);

  p2–>hide();

  attach(*adp1);

}

В этом классе существуют четыре обратных вызова. Каждый из них проявляется в том, что нажатая кнопка исчезает и вместо нее появляется новая. Однако это достигается четырьмя разными способами.

voidW7::sh() // скрывает кнопку, показывает следующую

{

  if (sh_left) {

    p1–>hide();

    p2–>show();

  }

  else {

    p1–>show();

    p2–>hide();

  }

  sh_left = !sh_left;

}

void W7::mv() // перемещает кнопку

{

  if (mv_left) {

    mvp–>move(100,0);

  }

  else {

    mvp–>move(–100,0);

  }

  mv_left = !mv_left;

}

void W7::cd() // удаляет кнопку и создает новую

{

  cdp–>hide();

  delete cdp;

  string lab = "create";

  int x = 100;

  if (cd_left) {

    lab = "delete";

    x = 200;

  }

  cdp = new Button(Point(x,300), 50, 20, lab, cb_cd);

  attach(*cdp);

  cd_left = !cd_left;

}

void

На этом сайте Вы можете читать книги онлайн бесплатно русская версия Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп.
Книги, аналогичгные Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп

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