Я подвергаю слишком много итераторов?
В моем классе могут быть дети, поэтому мне нужно выставить итераторы. Класс рендеринга должен отменить итерацию, поэтому у меня есть обратные итераторы. Но есть ли способ иметь меньше таких, потому что это похоже на много:
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;
Спасибо
Ответы
Ответ 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() и т.д.