Абстрактная оболочка для контейнеров stl? - PullRequest
6 голосов
/ 16 марта 2011

Я бы хотел представить некоторые объекты как абстрактные контейнеры с возможностями манипуляции в стиле stl (циклы for_each, итераторы) и скрыть детали реализации контейнера.

Проблемы производительности не имеют значения (допустимы виртуальные вызовы и даже выделение памяти при копировании «универсального» итератора).

Я собираюсь написать абстрактный интерфейс контейнера с чисто виртуальными функциями (+ «универсальный» итератор над контейнером) и адаптером реализации для последовательных контейнеров stl.

Но, может быть, есть полезные библиотеки для этой цели?

Или это вообще плохая идея?

Ответы [ 5 ]

2 голосов
/ 23 марта 2011
1 голос
/ 16 марта 2011

Вот моя оболочка прямого итератора для стиля Java, реализованная одна.Это ужасно.Вспомогательные части не являются обязательными и могут быть переработаны.

1 голос
/ 16 марта 2011

Если ваши "объекты" - это не объекты STL, а пользовательские, я думаю, это хорошая идея.

Как вы можете видеть на http://www.sgi.com/tech/stl/Vector.html, вектор "является моделью" RandomAccessContainer. Большинство пакетов Boost используют схожие концепции (термин «концепция»)

В C ++ у вас есть две возможности сделать это:

  • Абстрактный класс (интерфейс), как вы предложили
  • Шаблоны

С шаблонами вы можете сделать что-то вроде:

doSomething < AnythingThatIsIterable >(AnythingThatIsIterable i){
    for (AnythingThatIsIterable::itertaor it = i.begin(); it != i.end(); ++i){
        it->foo()
    }
}
  • Будет работать любой класс, который предоставляет итератор, начало и конец: std :: vector, но также и ваши собственные объекты.
  • Эти объекты не должны наследоваться от какого-либо интерфейса, поэтому std :: vector будет работать.
0 голосов
/ 23 марта 2011

Я полностью понимаю вопрос пользователя. Он / она хочет создать собственный класс-контейнер, который предоставляет пользователю STL-подобный интерфейс. Стандартных контейнеров STL не хватает каким-либо образом, и поэтому они не являются подходящим выбором.

Например, у меня есть класс интерфейса для «Dataline» с именем IDataline. Реализация интерфейса IDataLine берет при построении строку с разделителями, анализирует ее и предоставляет список полей. через const_iterator с семантикой forward_iterator_tag. Ни один контейнер STL не может сделать это из коробки.

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

Я определил интерфейс IDataline следующим образом:

 1 class IDataline
 2 {
 3 public:
 4    class const_iterator 
 5    {
 6      public: 
 7           virtual const_iterator& operator=(const const_iterator& rhs) =0;
 8           virtual bool operator==(const const_iterator& rhs) =0;
 9           virtual bool operator!=(const const_iterator& rhs) =0;
10           virtual const_iterator& operator++() =0;
11           virtual const_iterator  operator++(int) =0;
12           virtual const Field& operator*() =0;
13           virtual const Field* operator->() =0;
14           virtual const Field& operator[](size_t idx) =0;
15           virtual size_t offset() =0;
16    }; 
17
18    virtual const_iterator begin() =0;
19    virtual const_iterator end() = 0;
20 };

Проблема может быть замечена в строках 11, 18 и 19 - нам нужно иметь возможность вернуть const_iterator, для которого требуется конструктор копирования, но, поскольку он является виртуальным, нет ни конструктора по умолчанию, ни конструктора копирования (для тип интерфейса) и компилятор (правильно) балки.

Вы можете утверждать, что я мог бы определить begin () и end () как:

virtual const_iterator& begin() = 0;
virtual const_iterator& end() = 0;

Затем я могу создать два экземпляра специализированного итератора на специализированном хосте и вернуть ссылки (или указатели для тех, кто предпочитает их), чтобы заставить это работать для моего случая.

Проблема в том, что такая реализация не удовлетворяет всем требованиям для прямых итераторов и будет нарушаться в более общих случаях использования, которые основаны на семантике прямых итераторов.

Есть два способа, которые я нашел после небольшого раздумья (и коллеги проконсультировались), что это можно решить:

  1. Должен ли ваш хост-класс быть полностью абстрактным? Если вы можете минимизировать абстракцию до того поведения, которое вам нужно изменить, то ваш инстанцируемый хост может встроить конкретный итератор (потому что экземпляр самого класса может быть создан), и у вас есть то, что вам нужно.

  2. Эдуардо Леон выше указывает, что сам итератор может быть упакован с использованием идиомы pimpl (Указатель на реализацию). В то время как есть много материалов, которые подробно описывают эту технику, Basilev в комментариях ниже предложение Леона указывает на то, что он не верит, что идиома pimpl сработает. Мой коллега предложил мне попробовать методику, поэтому я разработаю проверенный образец. Если это сработает, я поделюсь этим. Если нет, я подробно опишу опыт, полученный в образце, и подожду, пока кто-нибудь более опытный, чтобы оценить, применима ли pimpl в этом случае.

0 голосов
/ 16 марта 2011

Наиболее общим решением проблемы «предоставления класса C ++ таким образом, чтобы пользователям класса не приходилось перекомпилировать свои программы всякий раз, когда моя реализация класса изменяется», является шаблон pImpl.Для получения дополнительной информации: http://en.wikipedia.org/wiki/Opaque_pointer

...