Почему в STL нет интерфейса "Iterable"? - PullRequest
10 голосов
/ 18 октября 2010

C ++ STL, похоже, не использует чисто абстрактные базовые классы (или интерфейсы) очень часто. Я знаю, что большинство вещей может быть достигнуто с помощью алгоритмов STL или умного метапрограммирования шаблонов.

Но, тем не менее, для некоторых случаев использования (например, в API, если я не хочу быть конкретным в отношении типа получаемого контейнера, просто в отношении элементов, которые он содержит), интерфейс следующей формы будет хороший:

template<typename T> struct forward_iterable {
    struct iterator {
        typedef T  value_type;
        typedef T& reference;
        typedef T* pointer;
        virtual reference operator*() const = 0;
        virtual pointer operator->() const = 0;
        virtual bool operator==(const iterator&) const = 0;
        virtual bool operator!=(const iterator&) const = 0;
        virtual operator const_iterator() const = 0;
        virtual iterator& operator++() = 0;
        virtual iterator  operator++(int) = 0;
    };
    struct const_iterator { ... };  // similar, but with const references

    virtual iterator begin() = 0;
    virtual const_iterator begin() const = 0;
    virtual iterator end() = 0;
    virtual const_iterator end() const = 0;
};

Если контейнеры STL реализуют этот класс как не виртуальную функцию, это, на мой взгляд, не повлияет на производительность (если я использую контейнеры напрямую, а не через этот интерфейс). Так почему же в STL так мало «интерфейсов»? Или я просто слишком много думаю в терминах "Java"?

Ответы [ 3 ]

7 голосов
/ 18 октября 2010

STL (который является подмножеством стандартной библиотеки) вообще не использует ООП (как в полиморфизме времени выполнения), и это специально.

С вашим дизайном не будет проблем с возвратом итераторов позначение (ковариация не работает для типов значений)?То есть, не обязательно ли все это должно полагаться либо на статические члены (которые вы можете вернуть по ссылке), либо на итераторы, размещенные в куче?Последнее может показаться довольно неуклюжим на языке без сбора мусора.

То, что вы описываете (итератор на основе типа значения), может быть достигнуто с помощью метода, называемого стиранием типа (и вы можете найти any_iterator реализации там) так же, как типы function и any boost.

Основная идея:

 //less templated interface
 template <class T>
 class any_iterator_base
 {
     virtual void increment() = 0;
     /*...*/
 };

 //derived class templated on iterator type
 template <class Iter, class T>
 class any_iterator_impl: public any_iterator_base<T>
 {
     Iter it;
     virtual void increment() { ++it; }
     /*...*/
 };

 //and a class for the user which makes it all act like a regular value type
 template <class T>
 class any_iterator
 {
     shared_ptr<any_iterator_base<T> > it;
 public:
     template <class Iter>
     any_iterator(Iter iterator): it(new any_iterator_impl<Iter, T>(iterator)) {}
     any_iterator& operator++() { it->increment(); return *this; }
     //...
 };

 int main()
 {
      std::vector<int> vec;
      any_iterator<int> it = vec.begin();
      //...
 }

Это может быть сложнее, чем это (например, нужно что-то делатьоб описании и применении категории итераторов? как будет работать сравнение двух any_iterators (двойная отправка / RTTI?)).

3 голосов
/ 18 октября 2010

Причина, по которой вы не видите много абстрактных базовых классов в стиле "интерфейс" в STL, заключается в том, что он так сильно зависит от шаблонов C ++.Когда вы используете шаблоны C ++, практически любой класс, независимо от его происхождения, будет работать, если он поддерживает все методы, которые пытается использовать шаблон.

Существует некий подразумеваемый интерфейс,но на самом деле писать это не нужно.В моем собственном кодировании я склонен писать так или иначе, просто для удобства пользователя, но это не то, как пишут авторы STL.

0 голосов
/ 18 октября 2010

Структуры STL не определены с учетом наследования.Нелегко сделать хороший пример для подклассов любой из коллекций stl.с учетом этого stl не заставляет вас «оплачивать» любые расходы, которые могли бы быть связаны с обычным наследованием классов.Если бы использовались виртуальные методы, оптимизатор не мог бы их встроить.

Кроме того, STL хочет быть совместимым с вещами, которые не могут наследоваться от абстрактного базового класса верхнего уровня, такими как массивы.

...