Анимация
JavaScript
|
Главная Библионтека public: class Iterator { Базовый класс внешнего итератора public: virtual bool More() = 0; virtual Type* Next() = 0; Iterator* SetBase::ProvideIterator() return new InternalIterator(this); void SetBase::AddObject(void* entry) void* v; History* h; if (At(entry, v)) { Уже есть - проверить время h = (History*)v; if (!h->Exists()) Необходимо выполнить вставку h->Insert(Timestamp()); else { Еще нет h = new History; h->Insert(Timestamp()); AddEntry(entry, h); void SetBase::RemoveObject(void* entry) void* v; History* h; if (At(entry, v)) { Уже есть - проверить время h = (History*)v; if (h->Exists()) Необходимо выполнить удаление h->Remove(Timestamp()); bool SetBase::Exists(void* entry, Timestamp ts) void* v; return At(entry, v) && ((History*)v)->Exists(ts); bool SetBase::Exists(void* entry) void* v; return At(entry, v) && ((History*)v)->Exists(); Существуют и другие возможности, которые можно было добавить, но и показанного вполне хватит для демонстрации рассматриваемой методики. Внутренний итератор Чтобы реализовать функцию ProvideIterator(), мы создаем как нетипизированный внутренний итератор, ограниченный файлом .cpp и производный от SetBase::Iterator, так и внешний - в виде параметризованной, безопасной по отношению к типам оболочки. Ниже приведен код внутреннего итератора, объявленного статически (то есть локального по отношению к файлу .cpp). Вся логика временных пометок спрятана в реализации этого класса. В файле set.cpp class InternalIterator : public SetBase::Iterator { private: Dictionary* dictionary; Dictionary::Slot* slot; Текущая позиция Timestamp my time; Время рождения данного итератора public: InternalIterator(Dictionary* d) : dictionary(d), s1ot(d->First()), my time() {} virtual bool More(); virtual void* Next(); bool InternalIterator::More() void* key; void* h; if (!dictionary->GetCurrent(s1ot, key, h)) return false; позиция выходит за текущие границы if (((History*)h)->Exists(my time)) return true; while (dictionary->GetNext(s1ot, key, h)); return false; void* InternalIterator::Next() void* key; void* keyl; void* h; Предполагается, что клиент сначала вызвал More(), поэтому объект GetNext() не устарел dictionary->GetCurrent(s1ot, key, h); dictionary->GetNext(s1ot, keyl, h); return key; Параметризованная оболочка, безопасная по отношению к типам Наконец, в приведенном ниже параметризованном классе все становится безопасным по отношению к типам и начинает радовать глаз. Внешний итератор представляет собой параметризованную оболочку для внутреннего итератора, предоставляемого SetBase. template <c1ass Type> class Set : private SetBase { public: Безаргументный конструктор - подходит Конструктор копий по умолчанию - подходит Оператор = по умолчанию - тоже подходит Set<Type>& operator+=(Type* object) { AddObject(object); return *this; } Set<Type>& operator-=(Type* object) { RemoveObject(object); return *this; } bool operator>=(Type* object) { return Exists(object); } class Iterator { private: SetBase::Iterator* iter; public: Iterator(Set&* i) : iter(s.ProvideIterator()) {} bool More() { return iter->More(); } Type* Next() { return (Type*)(iter->Next()); } Iterator* ProvideIterator() { return new Set::Iterator(*this); } Существуют и другие возможности, которые было бы неплохо добавить в параметризованный класс, но я думаю, что вы поняли общий принцип. От подобных параметризованных классов редко создаются производные, поэтому вложенный класс итератора оформлен с использованием подставляемых функция. В сущности, этот итератор можно просто объявить в стеке: Set::Iterator iter(aSet); Такой вариант работает вполне нормально, однако он не соответствует обычной идиоме возвращения итератора из коллекции. Заслуживает внимания и другой вариант: сделать SetBase переменной класса вместо закрытого базового класса. Это позволит вам упрятать SetBase в файл .cpp, чтобы клиент никогда не видел его. Для этого в шаблоне Set придется определить конструкторы и оператор =, но все остальные модификации шаблона будут простыми и незамысловатыми. 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 [ 40 ] 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |