С++ - язык, который изучается постепенно.Убогие,но распространенные варианты


Материалы книги получены с http://www.itlibitum.ru/

Убогие, но распространенные варианты

Вряд ли вы встретите в коммерческих библиотеках классов итераторы именно в таком виде. У каждого находится свой подход к этой теме. Ниже перечислены некоторые варианты, которые часто встречаются в странствиях по С++, с краткими комментариями по поводу их достоинств и недостатков.

Мономорфные активные итераторы вне области действия

Даже жалко расходовать замечательный термин на такую простую концепцию. Итераторы называются мономорфными, поскольку в них не используются виртуальные функции, и находятся вне области действия, поскольку они не объявляются вложенными в коллекцию.

class Collection { ... };

class CollectionIterator {

private:

Collection* coll;

public:

CollectionIterator(Collection* coll);

bool More();

Foo* Next();

};

CollectionIterator iter(collection); // Создать итератор

while (iter.More())

f(iter.Next());

Просто удивительно, что всего несколько строк программы порождает столько проблем:

При использовании класса, производного от Collection, каждый клиент должен знать, какие

новые классы итераторов должны использоваться вместо старого CollectionIterator.

Переменные класса итератора видны всем и каждому. Даже если они не составляют

государственной тайны, весь клиентский код придется перекомпилировать каждый раз, когда

вам захочется изменить реализацию итератора.

Занесение итераторов в стек противоречит некоторым стратегиям многопоточности,

рассматриваемым в следующей главе.

Многократное использование такого кода - задача мерзкая.

Учитывая все это, будет намного, намного лучше попросить класс коллекции: «Пожалуйста, сэр, сделайте мне итератор» вместо того, чтобы самому создавать его в стеке. Невзирая на все проблемы, этот тип итераторов часто встречается в коммерческих библиотеках классов.

Пассивные итераторы типа void*

Самая распространенная вариация на тему пассивных итераторов - не возиться с предварительным объявлением класса итератора, а обмануть клиентов и внушить им, что на самом деле они имеют дело с типом void*. Все это часто маскируется каким-нибудь красивым именем с помощью typedef, но уродливый void* так легко не спрячешь.

typedef void* AprilInParis;

class Collection {

public:

AprilInParis Iterate(); // Возвращает загримированный void*

bool More(AprilInParis&);

Foo* Next(AprilInParis&);

};

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

Нетипизированные значения функции Next()

Многие классы итераторов пишутся в обобщенной форме для типа void* или какого-то абстрактного базового класса. Клиент должен сам приводить значение, возвращаемое функцией Next(), обратно к правильному типу - и горе ему, если он что-нибудь напутает. Шаблоны изобретались именно для этой цели, так что теперь подобный бред уже нельзя оправдать.


Назад    Содержание    Далее    

Copyright 2005. Климов Александр. All Right Reserved.
Сайт создан в системе uCoz