Подтвердить что ты не робот

Я подвергаю слишком много итераторов?

В моем классе могут быть дети, поэтому мне нужно выставить итераторы. Класс рендеринга должен отменить итерацию, поэтому у меня есть обратные итераторы. Но есть ли способ иметь меньше таких, потому что это похоже на много:

std::vector<AguiWidget*>::iterator          getChildBeginIterator();
std::vector<AguiWidget*>::reverse_iterator  getChildRBeginIterator();
std::vector<AguiWidget*>::iterator          getChildEndIterator();
std::vector<AguiWidget*>::reverse_iterator  getChildREndIterator();

std::vector<AguiWidget*>::const_iterator            getChildBeginIterator() const;
std::vector<AguiWidget*>::const_reverse_iterator    getChildRBeginIterator() const;
std::vector<AguiWidget*>::const_iterator            getChildEndIterator() const;
std::vector<AguiWidget*>::const_reverse_iterator    getChildREndIterator() const;

std::vector<AguiWidget*>::iterator          getPrivateChildBeginIterator();
std::vector<AguiWidget*>::reverse_iterator  getPrivateChildRBeginIterator();
std::vector<AguiWidget*>::iterator          getPrivateChildEndIterator();
std::vector<AguiWidget*>::reverse_iterator  getPrivateChildREndIterator();

std::vector<AguiWidget*>::const_iterator            getPrivateChildBeginIterator() const;
std::vector<AguiWidget*>::const_reverse_iterator    getPrvateChildRBeginIterator() const;
std::vector<AguiWidget*>::const_iterator            getPrivateChildEndIterator() const;
std::vector<AguiWidget*>::const_reverse_iterator    getPrivateChildREndIterator() const;

Спасибо

4b9b3361

Ответ 1

Те, которые выглядят хорошо для меня. Или я не могу более точно комментировать, не зная, что именно вы делаете. Но одна вещь, которую вы, безусловно, можете сделать в любом случае: почему бы вам не использовать typedef? Если вы используете typedef, вы можете использовать его вне класса, а значит, в клиентском коде, где вы бы использовали класс!

Например,

class sample
{
public:

  //make these typedef public so you use it from outside!
  typedef std::vector<AguiWidget*>::iterator  iterator ;
  typedef std::vector<AguiWidget*>::reverse_iterator reverse_iterator;
  typedef std::vector<AguiWidget*>::const_iterator const_iterator;
  typedef std::vector<AguiWidget*>::const_reverse_iterator const_reverse_iterator;

  iterator           child_begin();
  reverse_iterator   child_rbegin();
  iterator           child_end();
  reverse_iterator   child_rend();

  const_iterator            child_begin() const;
  const_reverse_iterator    child_rbegin() const;
  const_iterator            child_end() const;
  const_reverse_iterator    child_rend() const;
};

//Usage
sample s;
sample::iterator it= s.child_begin(); 
//see this ^^^^^^^^ how we use the typedef here!

Это выглядит лучше! В основном typedef инкапсулирует реализацию, поскольку она помогает вам скрыть детали реализации класса; например, какой контейнер вы используете в классе, std::vector, std::list или что? См. Еще раз иллюстрации использования выше; просто взглянув на него, вы не можете сказать тип контейнера, не так ли?

Обратите внимание, что я также изменил имя функции. Я думаю, что все в порядке. В конце концов, STL использует только begin и end в отличие от beginIterator и endIterator. Тем не менее, нижний регистр - мой вкус, вы все же можете предпочесть верхний регистр для согласованности!

По-моему, функции const не имеют большого смысла, вам, вероятно, понадобится следующий набор функций, если вы хотите выставить итераторы только для чтения!

const_iterator            readonly_child_begin();
const_reverse_iterator    readonly_child_rbegin();
const_iterator            readonly_child_end();
const_reverse_iterator    readonly_child_rend();


//Usage
sample s;
sample::const_iterator cit= s.readonly_child_begin(); 
//see this ^^^^^^^^ how we use the typedef here!

Ответ 2

Нет ответа, но задайте себе следующие вопросы:

  • Планируете ли вы использовать каждый итератор?
  • Вам нужна разница между дочерним и частным дочерними элементами?
  • Вам нужно выставить что-то, называемое частным ребенком?
  • Не индексирование было бы более удобным, чем итерация?

В противном случае это кажется совершенно прекрасным; итераторы могут потребовать много кода в классе, но сделать его удобным для использования. (Вы должны увидеть мои полиморфные итераторы, поддерживающие XQuery, для коллекций XML, которые переносят несколько разных итераторов, не совместимых с STL, из сторонних библиотек...)

Предложение typedef, предложенное несколькими комментаторами, является хорошей идеей, потому что оно дает лучшую инкапсуляцию, даже если эта инкапсуляция не выполняется компилятором.

Ответ 3

Простым способом разрезать этот интерфейс пополам является использование диапазонов вместо пар begin()/end(). Например, см. Boost iterator_range. Или вы можете вернуть ссылку на контейнер, но тогда вы можете либо получить только const_iterator, либо вы можете позволить внешнему изменять контейнер, который вам может не понадобиться.

Обратите внимание, что векторные итераторы двунаправлены, поэтому вы можете снова уменьшить количество методов, не подвергая меньшую функциональность. Если вам действительно нужно использовать ++ вместо --, вы можете использовать для этого фасад, например Boost reverse_iterator.

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

В любом случае для меня очень разумны 4 функции вместо 16 звуков.

Ответ 4

Вы можете достичь этого через интерфейс mixin:

template<int Tag> class IteratorRange {
  private:
    std::vector<AguiWidget*>& range;
  public:
    IteratorRange(std::vector<AguiWidget*>& range) : range(range) {}

    typedef std::vector<AguiWidget*>::iterator  iterator ;
    typedef std::vector<AguiWidget*>::reverse_iterator reverse_iterator;
    typedef std::vector<AguiWidget*>::const_iterator const_iterator;
    typedef std::vector<AguiWidget*>::const_reverse_iterator const_reverse_iterator;

    iterator           begin();
    reverse_iterator   rbegin();
    iterator           end();
    reverse_iterator   rend();
};

enum { PublicChild, PrivateChild };
class MyClass : public IteratorRange<PublicChild>, private IteratorRange<PrivateChild> {
  MyClass() : IteratorRange<PublicChild>( ??? ), IteratorRange<PrivateChild>( ??? ) { }
  typedef IteratorRange<PublicChild> Public; // For MyClass::Public::begin etc
};

Ответ 5

В зависимости от того, что вы делаете с этими итераторами, вы можете выявить некоторые функции посетителя:

template<class UnaryFunction>
void visit(UnaryFunction & f) {
    // apply function to each element in vector
}

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

Ответ 6

Да, в основном. Это также делают стандартные контейнеры библиотек. Добро пожаловать на С++!

Однако я бы пересмотрел "private". Я даже не могу сказать, какими они должны быть, но это не может быть хорошо.

Я бы также добавил некоторые псевдонимы типа члена с ключевым словом typedef, чтобы сделать тип возврата более инкапсулированным.

Ответ 7

Вы уже раскрываете std::vector:: iterator, это означает, что вы уже раскрываете многие детали реализации.

Возврат const std::vector &, ссылка const может уменьшить большую часть интерфейса и обеспечить больше функциональности. В противном случае вам может понадобиться добавить что-то вроде getChildSize(), getXXXSize() и т.д.