Анимация
JavaScript


Главная  Библионтека 

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

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