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

 Логически разные операции имеют разные имена. И опять-таки, несмотря на то, что это очевидно, существуют вопросы: почему мы связываем объект класса Shape с объектом класса Window, но добавляем объект класса Line к объекту класса Shape? В обоих случаях мы “помещаем нечто во что-то”, так почему бы не назвать такие операции одинаково? Нет. За этой схожестью кроется фундаментальная разница. Рассмотрим пример.


Open_polyline opl;

opl.add(Point(100,100));

opl.add(Point(150,200));

opl.add(Point(250,250));


Здесь мы копируем три точки в объект opl. Фигуре opl безразлично, что будет с нашими точками после вызова функции add(); она хранит свои собственные копии этих точек. На самом деле мы редко храним копии точек, а просто передаем их фигуре. С другой стороны, посмотрим на следующую инструкцию:


win.attach(opl);


Здесь мы создаем связь между окном win и нашей фигурой opl; объект win не создает копию объекта opl, а вместо этого хранит ссылку на него. Итак, мы должны обеспечить корректность объекта opl, поскольку объект win использует его. Иначе говоря, когда окно win использует фигуру opl, оно должно находиться в ее области видимости. Мы можем обновить объект opl, и в следующий раз объект win будет рисовать фигуру opl с изменениями. Разницу между функциями attach() и add() можно изобразить графически.



Функция add() использует механизм передачи параметров по значению (копии), а функция attach() — механизм передачи параметров по ссылке (использует общий объект). Мы могли бы решить копировать графические объекты в объекты класса Window. Однако это была бы совсем другая модель программирования, которая определяется выбором функции add(), а не attach(). Мы решили просто связать графический объект с объектом класса Window. Это решение имеет важные последствия. Например, мы не можем создать объект, связать его, позволить его уничтожить и ожидать, что программа продолжит работать.


void f(Simple_window& w)

{

  Rectangle r(Point(100,200),50,30);

  w.attach(r);

} // Ой, объекта r больше нет


int main()

{

  Simple_window win(Point(100,100),600,400,"Мое окно");

  // ...

  f(win); // возникают проблемы

  // ...

  win.wait_for_button();

}


  Пока мы выходили из функции f() и входили в функцию wait_for_button(), объект r для объекта win перестал существовать и соответственно выводиться на экран. В главе 17 мы покажем, как создать объект в функции и сохранить его между ее вызовами, а пока должны избежать связывания с объектом, который исчез до вызова функции wait_for_button(). Для этого можно использовать класс Vector_ref, который рассматривается в разделах 14.10 и Г.4.

Обратите внимание на то, что если бы мы объявили функцию f() так, чтобы она получала константную ссылку на объект класса Window (как было рекомендовано в разделе 8.5.6), то компилятор предотвратил бы ошибку: мы не можем выполнить вызов attach(r) с аргументом типа const Window, поскольку функция attach() должна изменить объект класса Window, чтобы зарегистрировать связь между ним и объектом r

14.1.4. Изменяемость

Основные вопросы, на которые следует ответить, проектируя классы, звучат так: кто может модифицировать данные и как он может это делать? Мы должны гарантировать, что изменение состояния объекта будет осуществляться только членами его класса. Именно для этого предназначены разделы public и private, но мы продемонстрируем еще более гибкий и тонкий механизм, основанный на ключевом слове protected. Это значит, что мы не можем просто включить в класс какой-то член, скажем, переменную label типа string; мы должны также решить, следует ли открыть его для изменений после создания объекта, и если да, то как. Мы должны также решить, должен ли другой код, кроме данного класса, иметь доступ к переменной label, и если да, то как. Рассмотрим пример.


struct Circle {

  // ...

private:

  int r; // radius

};


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

c.r = –9; // OK? Нет — ошибка компилирования: переменная Circle::r

          // закрыта


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