Материалы книги получены с http://www.itlibitum.ru/
Перебор графа объектов
В дальнейшем мы воспользуемся методикой виртуальных функций из приведенного выше списка, хотя материал с таким же успехом применим и к объектам классов. Перечисление реализуется двумя основными способами: с применением рекурсивных функций и функторов, а также с применением итераторов.
Рекурсивные функции и функторы
Первая естественная реакция: организовать механизм косвенного вызова, создать функцию или функтор, вызываемые для каждого доступного объекта, и подождать, пока закончится рекурсивный перебор.
class Functor { // 'Функция' обратного вызова
public:
virtual void Apply(MotherOfAllClasses*) = 0;
};
class MotherOfAllClasses {
public:
// Применить fn к каждому доступному объекту
virtual void EachObject(Functor& fn);
};
Функция EachObject() вызывает fn.Apply(this), а затем вызывает EachObject() для каждого внедренного объекта или объекта, на который указывает переменная класса. Кроме того, EachObject() вызывает Base::EachObject() для каждого базового класса, таким образом члены
базового класса тоже включаются в перечисление. В зависимости от алгоритма в MotherOfAllClasses можно включить бит признака, показывающий, что объект был рассмотрен ранее. Впрочем, как мы вскоре убедимся, иногда без этого можно обойтись.
Итераторы
Более удачное решение - организовать возвращение объектом итератора для всех внедренных объектов (включая базовые классы), в том числе и тех, на которые непосредственно ссылаются его переменные.
class MOAOIterator { // "MotherOfAllObjectsIterator"
public:
virtual bool More() = 0;
virtual MotherOfAllObjects* Next() = 0;
};
class MotherOfAllObjects {
public:
virtual MOAOIterator* EachObject();
};
Конечно, на этот раз потребуется более хитроумный код, чем в варианте с виртуальными функциями из последнего раздела. Тем не менее, методика «итераторы всюду» обладает одним громадным преимуществом: она позволяет выполнять действия последовательно. Вариант с рекурсивными функциями не позволяет каждую миллисекунду или около того делать передышку и давать поработать другому коду. При использовании итераторов, если соблюдать осторожность, это не проблема. Далее мы будем использовать именно этот вариант.
Назад Содержание Далее
|