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

Программирование. Принципы и практика использования 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

Перейти на страницу:

Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Программирование. Принципы и практика использования C++ Исправленное издание - Бьёрн Страуструп, относящееся к жанру Программирование. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.

Комментарии (0)