Трудно иметь динамический полиморфизм с итераторами в стиле C ++. operator++(int)
возвращает по значению, что на самом деле сложно: у вас не может быть виртуальной функции-члена, которая возвращает *this
по значению без ее нарезки.
Если возможно, я рекомендую использовать шаблоны, как все говорят.
Однако если вам нужен динамический полиморфизм, например, потому что вы не можете представить реализацию add_all_msgs как шаблон, то я думаю, что вы могли бы притвориться Java, например:
struct MessageIterator {
virtual Message &get() = 0;
virtual void next() = 0;
// add more functions if you need more than a Forward Iterator.
virtual ~MessageIterator() { }; // Not currently needed, but best be safe
};
// implementation elsewhere. Uses get() and next() instead of * and ++
void add_all_msgs(MessageIterator &it);
template <typename T>
struct Adaptor : public MessageIterator {
typename T::iterator wrapped;
Adaptor(typename T::iterator w) : wrapped(w) { }
virtual Message &get() {
return *wrapped;
}
virtual void next() {
++wrapped;
}
};
int main() {
std::deque<Message> v;
Adaptor<std::deque<Message> > a(v.begin());
add_all_msgs(a);
}
Я проверил, что это компилируется, но я не проверял и никогда раньше не использовал этот дизайн. Я также не беспокоился о константности - на практике вы, вероятно, хотите const Message &get() const
. И в данный момент у адаптера нет возможности узнать, когда остановиться, но также и код, с которого вы начали, так что я тоже проигнорировал это. В основном вам понадобится функция hasNext
, которая сравнивает wrapped
с конечным итератором, предоставленным конструктору.
Возможно, вы сможете что-то сделать с помощью функции шаблона и ссылок на const, чтобы клиенту не приходилось знать или объявлять этот неприятный тип адаптера.
[Edit: если подумать, возможно, лучше иметь шаблон функции-заглушки add_all_msgs
, который оборачивает свой параметр в адаптере и затем вызывает real_add_all_msgs
. Это полностью скрывает адаптер от клиента.]