|
Перебор графа объектов В дальнейшем мы воспользуемся методикой виртуальных функций из приведенного выше списка, хотя материал с таким же успехом применим и к объектам классов. Перечисление реализуется двумя основными способами: с применением рекурсивных функций и функторов, а также с применением итераторов. Рекурсивные функции и функторы Первая естественная реакция: организовать механизм косвенного вызова, создать функцию или функтор, вызываемые для каждого доступного объекта, и подождать, пока закончится рекурсивный перебор. 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(); }; Конечно, на этот раз потребуется более хитроумный код, чем в варианте с виртуальными функциями из последнего раздела. Тем не менее, методика «итераторы всюду» обладает одним громадным преимуществом: она позволяет выполнять действия последовательно. Вариант с рекурсивными функциями не позволяет каждую миллисекунду или около того делать передышку и давать поработать другому коду. При использовании итераторов, если соблюдать осторожность, это не проблема. Далее мы будем использовать именно этот вариант. |
Copyright 2006. Климов Александр. All Right Reserved.