Категории
Самые читаемые
Лучшие книги » Компьютеры и Интернет » Программирование » Язык программирования C++. Пятое издание - Стенли Липпман

Язык программирования C++. Пятое издание - Стенли Липпман

Читать онлайн Язык программирования C++. Пятое издание - Стенли Липпман

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 172 173 174 175 176 177 178 179 180 ... 297
Перейти на страницу:

Операторы присвоения, использующие копию и обмен, автоматически устойчивы к исключениям и правильно отрабатывают присвоение себя себе.

Упражнения раздела 13.3

Упражнение 13.29. Объясните, почему вызов функции swap() в вызове swap(HasPtr&, HasPtr&) не приводит к бесконечной рекурсии.

Упражнение 13.30. Напишите и проверьте функцию swap() для подобной значению версии класса HasPtr. Снабдите свою функцию swap() оператором вывода примечания о ее выполнении.

Упражнение 13.31. Снабдите свой класс оператором < и определите вектор объектов класса HasPtr. Вставьте в вектор несколько элементов, а затем отсортируйте его (sort()). Обратите внимание на то, когда вызывается функция swap().

Упражнение 13.32. Получит ли преимущества подобная указателю версия класса HasPtr от определения собственной функции swap()? Если да, то в чем это преимущество? Если нет, то почему?

13.4. Пример управления копированием

Несмотря на то что управление копированием обычно необходимо для классов, резервирующих ресурсы, управление ресурсами не единственная причина определения этих функций-членов. У некоторых классов может быть необходимость в учете или других действиях, выполняемых функциями управления копированием.

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

Для отслеживания того, какие сообщения в каких папках находятся, каждый объект класса Message будет хранить набор указателей на объекты класса Folder, в которых они присутствуют, а каждый объект класса Folder будет содержать набор указателей на его объекты класса Message. Эту конструкцию иллюстрирует рис. 13.1.

Рис. 13.1. Проект классов Message и Folder

Класс Message будет предоставлять функции save() и remove() для добавления и удаления сообщений из папки. Для создания нового объекта класса Message следует определить содержимое сообщения, но не папку. Чтобы поместить сообщение в определенную папку, следует вызвать функцию save().

После копирования сообщения копия и оригинал будут разными объектами класса Message, но оба сообщения должны присутствовать в том же самом наборе папок. Таким образом, копирование сообщения скопирует содержимое и набор указателей на папку. Он должен также добавить указатель на недавно созданный объект класса Message к каждому из этих объектов класса Folder.

После удаления сообщения объект класса Message больше не существует. Поэтому его удаление должно удалять указатели на этот объект класса Message из всех объектов класса Folder, которые содержали это сообщение.

Когда один объект класса Message присваивается другому, содержимое (contents) левого сообщения заменяется таковым правого. Следует также модифицировать набор папок, удалив левый объект класса Message из предыдущих объектов класса Folder и добавив в них правый.

Глядя на этот список операций, можно заметить, что и деструктор, и оператор присвоения копии должны удалять заданное сообщение из папок, которые указывают на него. Точно так же и конструктор копий, и оператор присвоения копии добавляют объект класса Message в заданный список объекта класса Folder. Для решения этих задач определим пару закрытых вспомогательных функций.

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

Класс Folder будет нуждаться в аналогичных функциях-членах управления копированием для добавления и удаления себя из хранящих их объектов класса Message.

Проектирование и реализацию класса Folder оставим читателю в качестве самостоятельного упражнения, но будем подразумевать, что у него есть функции-члены addMsg() и remMsg(), выполняющие все действия по добавлению и удалению заданного сообщения из набора сообщений указанной папки.

Класс Message

С учетом проекта выше можно написать класс Message следующим образом:

class Message {

 friend class Folder;

public:

 // папки неявно инициализируются пустым набором

 explicit Message(const std::string &str = ""):

  contents(str) { }

 // функции управления копированием, контролирующие указатели на

 // это сообщение

 Message(const Message&);            // конструктор копий

 Message& operator=(const Message&); // присвоение копии

 ~Message();                         // деструктор

 // добавить/удалить это сообщение из набора сообщений папки

 void save(Folder&);

 void remove(Folder&);

private:

 std::string contents;      // фактический текст сообщения

 std::set<Folder*> folders; // папки, содержащие это сообщение

 // вспомогательные функции, используемые конструктором копий,

 // оператором присвоения и деструктором

 // добавить это сообщение в папки, на которые указывает параметр

 void add_to_Folders(const Message&);

 // удалить это сообщение из каждой папки в folders

 void remove_from_Folders();

};

Класс определяет две переменные-члена: contents — для хранения текста сообщения и folders — для хранения указателей на объекты класса Folder, в которых присутствует данное сообщение. Получающий строку конструктор копирует ее в переменную contents и (неявно) инициализирует переменную folders пустым набором. Поскольку у этого конструктора есть аргумент по умолчанию, он также является стандартным конструктором класса Message (см. раздел 7.5.1).

Функции-члены save() и remove()

Кроме функций управления копированием, у класса Message есть только две открытых функции-члена: save(), помещающая сообщение в данную папку, и remove(), извлекающая его:

void Message::save(Folder &f) {

 folders.insert(&f); // добавить данную папку в список папок

 f.addMsg(this);     // добавить данное сообщение в набор сообщений

}

void Message::remove(Folder &f) {

 folders.erase(&f); // удалить данную папку из списка папок

 f.remMsg(this);    // удалить данное сообщение из набора сообщений

}

Чтобы сохранить (или удалить) сообщение, требуется модифицировать член folders класса Message. При сохранении сообщения сохраняется указатель на данный объект класса Folder; при удалении сообщения этот указатель удаляется.

Эти функции должны также модифицировать заданный объект класса Folder. Модификация этого объекта является задачей, контролируемой классом Folder при помощи функций-членов addMsg() и remMsg(), которые добавляют или удаляют указатель на данный объект класса Message соответственно.

Управление копированием класса Message

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

// добавить это сообщение в папки, на которые указывает m

void Message::add_to_Folders(const Message &m) {

 for (auto f : m.folders) // для каждой папки, содержащей m,

  f->addMsg(this);        // добавить указатель на это сообщение

                          // в данную папку

}

Здесь происходит вызов функции addMsg() для каждого объекта класса Folder в m.folders. Функция addMsg() добавит указатель на этот объект класса Message в данный объект класса Folder.

1 ... 172 173 174 175 176 177 178 179 180 ... 297
Перейти на страницу:
На этой странице вы можете бесплатно скачать Язык программирования C++. Пятое издание - Стенли Липпман торрент бесплатно.
Комментарии