nonstandard iterator for subclass with containers of subclasses - c++

Apologies that this is pretty long, but I couldn't figure out how to make it shorter and still show the important features of my problem.
I'm asking this even though I have come up with an idea of how to do what I want, but it requires implementing an iterator in a way that doesn't match the standard iterator pattern. I would like to ask for any suggestions on how this could be done in a more standard or better way.
I have an abstract base class. Any subclass of it will have some collections of objects. There is some common code that I would like to put in the base class that needs to iterate over all of the objects in the collections. The objects in the collections will all descend from another abstract base class, but will be subclass objects. There may be multiple collections of objects from multible subclasses, and the collections may be different collection types. What I'd really like to do is something like this: (Note: this code will not compile.)
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool operator!=(iterator& other) = 0;
};
virtual iterator begin() = 0;
virtual iterator end() = 0;
int processCollections()
{
iterator it;
int sum = 0;
for(it = begin(); it != end(); ++it)
{
sum += (*it).someInterface(7);
}
return sum;
}
};
And then I want some subclasses of CollectionObjectBase and MyObjectBase like this:
class CollectionObject1 : public CollectionObjectBase { ... }
class CollectionObject2 : public CollectionObjectBase { ... }
class CollectionObject3 : public CollectionObjectBase { ... }
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::vector< CollectionObject2>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
class MyObjectB : public MyObjectBase
{
public:
std::vector<CollectionObject1> someThings;
std::set< CollectionObject3> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::vector<CollectionObject1>::iterator it1;
std::set< CollectionObject3>::iterator it2;
// Iterate first over it1 and then over it2.
...
};
virtual MyObjectBase::iterator begin()
{
return iterator(someThings.begin(), otherThings.begin());
}
virtual MyObjectBase::iterator end()
{
return iterator(someThings.end(), otherThings.end());
}
};
There are some big problems with the above code. First, MyObjectBase::begin() and MyObjectBase::end() can't return MyObjectBase::iterator because MyObjectBase::iterator is an abstract class, and you wouldn't want to anyway because you actually want a subclass of MyObjectBase::iterator that knows how to iterate over the collections in the subclass of MyObjectBase. You need to return a reference to MyObjectBase::iterator.
The second problem comes with MyObjectA::iterator::operator!=(). You'd like to do something like this:
virtual bool operator!=(iterator& other)
{
return it1 != other.it1 || it2 != other.it2;
}
But to be an overload of MyObjectBase::iterator::operator!=() it has to take a parameter of type MyObjectBase::iterator& and that doesn't have members it1 and it2. My best idea I've thought of to resolve this is to replace operator!=() with a function atEnd(), since the only thing it is being used for in this code is to detect if the iterator is at the end, but it makes it really non-standard.
Finally, MyObjectA::begin() and MyObjectA::end() cannot return a temporary. Remember, we have to return a reference to a MyObjectBase::iterator that points to a MyObjectA::iterator, not copy construct a MyObjectBase::iterator. My best idea I've thought of to resolve this is to allocate the iterator with new, and when I do that I need to return a pointer, not a reference so that the caller can delete it. So here's my final code. It works and performs the function of an iterator, but it is non-standard. Can anyone think of a way to do this with an iterator that fits the standard pattern?
#include <map>
#include <vector>
class CollectionObjectBase
{
public:
virtual int someInterface(int x) = 0;
};
class MyObjectBase
{
public:
class iterator
{
public:
virtual CollectionObjectBase& operator*() = 0;
virtual iterator& operator++() = 0;
virtual bool atEnd() = 0;
};
virtual iterator* begin() = 0;
int processCollections()
{
iterator* it;
int sum = 0;
for (it = begin(); !it->atEnd(); ++it)
{
sum += (**it).someInterface(7);
}
delete it;
return sum;
}
};
class CollectionObject1 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 1;
}
};
class CollectionObject2 : public CollectionObjectBase
{
public:
virtual int someInterface(int x)
{
return x + 2;
}
};
class MyObjectA : public MyObjectBase
{
public:
std::map<int, CollectionObject1> someThings;
std::vector< CollectionObject2> otherThings;
class iterator : public MyObjectBase::iterator
{
public:
std::map<int, CollectionObject1>::iterator it1;
std::map<int, CollectionObject1>::iterator it1End;
std::vector< CollectionObject2>::iterator it2;
std::vector< CollectionObject2>::iterator it2End;
iterator(std::map<int, CollectionObject1>::iterator it1Init, std::map<int, CollectionObject1>::iterator it1EndInit,
std::vector< CollectionObject2>::iterator it2Init, std::vector< CollectionObject2>::iterator it2EndInit) :
it1(it1Init),
it1End(it1EndInit),
it2(it2Init),
it2End(it2EndInit)
{
// Initialization handled by initialization list.
}
virtual CollectionObjectBase& operator*()
{
if (it1 != it1End)
{
return (*it1).second;
}
else
{
return *it2;
}
}
virtual iterator& operator++()
{
if (it1 != it1End)
{
++it1;
}
else
{
++it2;
}
return *this;
}
virtual bool atEnd()
{
return it1 == it1End && it2 == it2End;
}
};
virtual MyObjectBase::iterator* begin()
{
return new iterator(someThings.begin(), someThings.end(), otherThings.begin(), otherThings.end());
}
};
There's an issue with useless' answer. Consider these subclasses of Impl and Base:
class MyImpl : public Base::Iterator::Impl {
public:
MyImpl(std::vector<CollectionObjectSub>::iterator itInit) : it(itInit) {}
CollectionObjectBase& operator*() { return *it; }
void operator++() { ++it; }
// bool operator==(Base::Iterator::Impl const &other) const { it == other.it; }
bool operator==(MyImpl const &other) const { it == other.it; }
private:
std::vector<CollectionObjectSub>::iterator it;
};
class Sub : public Base {
public:
Iterator& begin() { return Iterator(new MyImpl(collection.begin())); }
private:
std::vector<CollectionObjectSub> collection;
};
Sub contains a vector and MyImpl contains a vector iterator. I'd like to instantiate a Base::Iterator with impl_ pointing at a MyImpl. If MyImpl::operator== takes a MyImpl& then it isn't overloading Base::Iterator::Impl::operator==, but if it takes a Base::Iterator::Impl& then I can't access the vector iterator even if it actually is a MyImpl.
It seems like I need to do a dynamic cast to get a MyImpl, which requires RTTI. I've heard to avoid using RTTI if possible. Is there another way?

So, you want to return an iterator by value, but have its dynamic type vary depending on the override of begin/end you called? No problem - just add another layer of indirection.
class Base {
public:
class Iterator {
public:
struct Impl {
virtual ~Impl() {}
virtual CollectionObjectBase& operator*() = 0;
virtual void operator++() = 0;
virtual bool operator==(Iterator::Impl const &other) const = 0;
};
Iterator() {}
explicit Iterator(std::unique_ptr<Impl> &&i) : impl_(std::move(i)) {}
Iterator(Iterator &&other) = default;
CollectionObjectBase& operator*() { return **impl_; }
Iterator& operator++() { ++*impl_; return *this; }
bool operator==(Iterator const &other) const {
return (!impl_ && !other.impl_) || (*impl_ == *other.impl_);
}
private:
std::unique_ptr<Impl> impl_;
};
// ...
This uses the pointer-to-impl (pimpl) idiom to give each concrete subclass of Base its own concrete subclass of Base::Iterator::Impl, but still let you pass Base::Iterator objects around by value using move semantics to transfer ownership of the dynamic object.
NB. I made two default-constructed (nullptr) iterators compare equal so you don't need to create a real instance for end.

Related

No known conversions

I'm have a problem with my constructors.
I get the following error:
no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >*’ to ‘std::multiset<std::__cxx11::basic_string<char> >::iterator {aka std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >}’
multiset.cpp:47:1: note: candidate: my_multiset::iterator::iterator()
my_multiset::iterator::iterator(void){}
multiset.h:17:10: note: no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >*’ to ‘const cpt323::my_multiset::iterator&’
multiset.h:17:10: note: candidate: constexpr my_multiset::iterator::iterator(cpt323::my_multiset::iterator&&)
multiset.h:17:10: note: no known conversion for argument 1 from ‘std::_Rb_tree_const_iterator<std::__cxx11::basic_string<char> >*’ to ‘my_multiset::iterator&&’
The code is working with the exception of this part, any suggestion on how to make the appropriate changes
class my_multiset : custom_datastructure
{
std::multiset<std::string> the_set;
std::multiset<std::string>::iterator head;
std::multiset<std::string>::iterator tail;
public:
class iterator : public custom_datastructure::iterator
{
std::multiset<std::string>::iterator current;
public:
iterator(void){};
iterator(std::multiset<std::string>::iterator a_set) : current(a_set)
{
}
};
multiset(void);
std::unique_ptr<custom_datastructure::iterator> begin(void)
{
head = the_set.begin();
return std::make_unique<my_multiset::iterator>(&head);
}
std::unique_ptr<custom_datastructure::iterator> end(void)
{
tail = the_set.end();
return std::make_unique<my_multiset::iterator>(&tail);
}
}
custom_datastructure is as below
struct datastructure
{
struct iterator
{
/** OPERATORS HERE **/
virtual std::unique_ptr<datastructure::iterator> operator++(void) = 0;
/** ETC **/
};
virtual std::unique_ptr<iterator> begin(void) = 0;
virtual std::unique_ptr<iterator> end(void) = 0;
}
Why is your code breaking?
The reason your code breaks is because unique_ptr can't be used as an iterator, so if you wrap your iterator in a unique_ptr when returning it from begin() and end(), then it isn't usable as an iterator anymore.
An iterator doesn't have to be a pointer; it just needs to act like one. In addition, an iterator shouldn't own data. A class owns data if the class is responsible for deleting that data, but an iterator shouldn't be responsible for deleting anything. It should just provide a way of accessing the data. This means that iterators can and should be passed around by value (instead of using std::unique_ptr).
How do we fix the design?
So here's the big question: are you trying to create an interface that returns some iterators, or are you trying to create an interface for things that act like iterators?
Creating an interface that returns some iterators
The most generic way to do this is through templates. The benefit of using templates is that it enables us to re-use this interface in a wide variety of situations, and we can #include the interface where we need it, without having any dependencies in the file defining the template.
template<class Iterator>
class Iterable {
public:
virtual Iterator begin() = 0;
virtual Iterator end() = 0;
};
We can use this to define my_multiset as returning iterators to std::multiset:
class my_multiset
: public Iterable<typename std::multiset<std::string>::iterator>
{
std::multiset<std::string> the_set;
public:
using iterator = typename std::multiset<std::string>::iterator;
iterator begin() override {
return the_set.begin();
}
iterator end() override {
return the_set.end();
}
};
Creating a GenericIterator<Value> - a class that can be assigned any iterator
Because pointers-to-iterators act like pointers, and not the underlying iterator, instead of using a unique_ptr<BaseIterator>, we're going to want to create a wrapper class that handles everything for us, while still acting like a normal iterator.
You'll be able to use it just like any old iterator, except that it can be assigned or created with an iterator to anything that derefences to Value. That means that the same GenericIterator can bind to a list iterator, a vector iterator, or even a std::multiset iterator.
Example showing how it could be used:
#include <iostream>
#include <list>
#include <vector>
int main()
{
std::vector<int> v{1, 2, 3};
std::list<int> l{10, 20, 30};
GenericIterator<int&> begin, end;
begin = v.begin();
end = v.end();
for (; begin != end; ++begin)
{
std::cout << *begin << " ";
}
begin = l.begin();
end = l.end();
for (; begin != end; ++begin)
{
std::cout << *begin << " ";
}
}
What parts do we need to make GenericIterator?
GenericIterator is going to store a pointer to a virtual base class. We'll also need a derived class that implements the base for a specific Iter.
Base class:
The base class virtualizes the main functions of an iterator: Increment, Dereference, and equality. It also provides a clone() method so that it's possible to make copies of iterators. close() comes in handy when writing a GenericIterator class that wraps this functionality.
template <class Value>
class IteratorBase
{
public:
virtual Value operator*() const = 0;
virtual IteratorBase& operator++() = 0;
virtual bool operator!=(IteratorBase const&) const = 0;
virtual bool operator==(IteratorBase const&) const = 0;
// We need this function for making copies of the iterator
virtual IteratorBase* clone() const = 0;
virtual ~IteratorBase() = default;
};
Derived class:
This derived class can wrap basically any other iterator on the planet, and it overrides all the methods in IteratorBase to give a fully-functioning iterator.
template <class Iter, class Value>
class IteratorDerived : public IteratorBase<Value>
{
Iter it;
public:
IteratorDerived() = default;
IteratorDerived(Iter it) : it(it) {}
IteratorDerived(IteratorDerived const&) = default;
IteratorDerived(IteratorDerived&&) = default;
Value operator*() const override { return *it; }
IteratorBase<Value>& operator++() override
{
++it;
return *this;
}
bool operator!=(IteratorBase<Value> const& other) const override
{
auto* derived = dynamic_cast<IteratorDerived const*>(&other);
return derived == nullptr || it != derived->it;
}
bool operator==(IteratorBase<Value> const& other) const override
{
auto* derived = dynamic_cast<IteratorDerived const*>(&other);
return derived != nullptr && it == derived->it;
}
IteratorBase<Value>* clone() const override
{
return new IteratorDerived(*this);
}
};
Generic Wrapper:
This GenericWrapper encapsulates all the functionality of an iterator, and because of how we're writing it, you can automatically assign any iterator that deferences to a matching value type.
template <class Value>
class GenericIterator
{
std::unique_ptr<IteratorBase<Value>> iterator;
public:
GenericIterator() = default;
GenericIterator(GenericIterator const& it) : iterator(it.iterator->clone())
{
}
GenericIterator(GenericIterator&&) = default;
// Creates a GenericIterator from an IteratorBase
explicit GenericIterator(IteratorBase<Value> const& it)
: iterator(it.clone())
{
}
// Creates a GenericIterator from an IteratorDerived
template <class Iter>
explicit GenericIterator(IteratorDerived<Iter, Value> const& it)
: iterator(it.clone())
{
}
// Creates a GenericIterator by wrapping another Iter
template <class Iter>
GenericIterator(Iter it) : iterator(new IteratorDerived<Iter, Value>(it))
{
}
GenericIterator& operator=(GenericIterator const& it)
{
iterator = std::unique_ptr<IteratorBase<Value>>(it.iterator->clone());
return *this;
}
GenericIterator& operator=(GenericIterator&&) = default;
Value operator*() const { return *(*iterator); }
GenericIterator& operator++()
{
++(*iterator);
return *this;
}
bool operator==(GenericIterator const& other) const
{
return *iterator == *other.iterator;
}
bool operator!=(GenericIterator const& other) const
{
return *iterator != *other.iterator;
}
};
Optional: C++17 template deduction guide
We can write a template type deduction guide for GenericIterator that automatically fills in the correct template parameter, making it easy to wrap any other iterator.
template<class Iter>
GenericIterator(Iter) -> GenericIterator<decltype(*std::declval<Iter>())>;

How do I make my iterator classes not look like container classes?

The premise
Say I have a container class Box which provides inner classes const_iterator and iterator. Because I want an iterator to be castable to a const_iterator, the latter inherits from the former:
class Box {
// ...
public:
class const_iterator : public std::iterator<std::random_access_iterator_tag, const int> { /* ... */ };
class iterator : public const_iterator { /* ... */ };
// ...
};
The problem
Now I want to test these classes using Google Test. Let's assert that the begin() and end() don't return the same thing:
const Box a;
EXPECT_NE(a.begin(), a.end());
Say hello to a compile error:
clang: no member named 'begin' in 'Box::const_iterator'
g++: ‘const class Box::const_iterator’ has no member named ‘begin’
The cause
Some research led me to this template in the Google Test source code (follow the link for expanded documentation):
typedef int IsContainer;
template <class C>
IsContainer IsContainerTest(int /* dummy */,
typename C::iterator* /* it */ = NULL,
typename C::const_iterator* /* const_it */ = NULL) {
return 0;
}
The result of this template magic is that if arguments to EXPECT_* have iterator and const_iterator member classes, then the type is assumed to be a container class. Knowing this, Google Test can print pretty human-readable reports when expectations fail, which is nice.
However, there's this little detail:
// Note that we look for both C::iterator and C::const_iterator. The
// reason is that C++ injects the name of a class as a member of the
// class itself (e.g. you can refer to class iterator as either
// 'iterator' or 'iterator::iterator'). If we look for C::iterator
// only, for example, we would mistakenly think that a class named
// iterator is an STL container.
so if I understand things right, this means that
Box::const_iterator has itself as a member class named const_iterator, and std::iterator as a memberclass named iterator.
Box::iterator has itself as a member class named iterator and Box::const_iterator as a member class named const_iterator.
Therefore both my iterator classes look like container classes to Google Test!
The question
How do I design my iterator classes to make them not look like containers?
Things I've tried:
Declaring the std::iterator superclass of const_iterator as private. This solves the problem for const_iterator by hiding the iterator member class, but it still doesn't let me pass a.begin() as a parameter to EXPECT_NE unless a is const. Seems like Google Test uses iterator begin() rather than const_iterator begin() const for some reason.
Removing the std::iterator superclass altogether. Is this a bad idea? I suppose I'll have to declare my std::iterator_traits manually, is there anything else I'll lose by not extending std::iterator?
Declaring the Box::const_iterator superclass of Box::iterator as private. This may or may not be an option since I'd have to redeclare methods I'd rather want to reuse (such as operator++).
Is there anything else I've overlooked?
The example
#include<iterator>
#include <memory> //unique_ptr<T>
#include <gtest/gtest.h>
class ThreeInts {
std::unique_ptr<int[]> v;
public:
ThreeInts() : v(new int[3]) { v[0] = 0; v[1] = 1; v[2] = 2; };
ThreeInts(int val) : ThreeInts() { v[0] = val; v[1] = val; v[2] = val; };
bool operator==(const ThreeInts& other) const {
return v[0] == other.v[0] && v[1] == other.v[1] && v[2] == other.v[2];
}
class const_iterator : public std::iterator<std::random_access_iterator_tag, const int> {
protected:
int* p;
public:
explicit const_iterator(int* p) : p(p) {}
const_iterator& operator++() { ++p; return *this; }
bool operator==(const const_iterator& rhs) const { return p == rhs.p; }
bool operator!=(const const_iterator& rhs) const { return p != rhs.p; }
int operator*() const { return *p; }
};
class iterator : public const_iterator {
public:
explicit iterator(int* p) : const_iterator(p) {}
int& operator*() const { return *p; }
};
iterator begin() { return iterator(v.get()); }
iterator end() { return iterator(v.get()+3); }
const_iterator begin() const { return const_iterator(v.get()); }
const_iterator end() const { return const_iterator(v.get()+3); }
};
TEST(ThreeInts, ThisTestCompilesAndPrettyFailureMessagesAreShown) {
const ThreeInts a(1), b(2);
ThreeInts c(1), d(2);
EXPECT_EQ(a, b);
EXPECT_EQ(a, c);
EXPECT_EQ(c, d);
}
TEST(ThreeInts, ThisTestCompilesIfTheStdIteratorParentIsPrivate) {
const ThreeInts a;
EXPECT_NE(a.begin(), a.end());
}
TEST(ThreeInts, ThisTestAlsoCompilesIfTheStdIteratorParentIsPrivateButItIsAHassle) {
ThreeInts a;
ThreeInts::const_iterator beg = a.begin();
ThreeInts::const_iterator end = a.end();
//EXPECT_NE(beg, end); // Compile error unless the std::iterator superclass is private
}
TEST(ThreeInts, ThisTestDoesNotCompileEvenIfTheStdIteratorParentIsPrivate) {
ThreeInts a;
//EXPECT_NE(a.begin(), a.end());
}
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
ThreeInts::iterator should not inherit from ThreeInts::const_iterator, instead they should be implemented separately.
class ThreeInts::iterator : public std::iterator< std::random_access_iterator_tag, int> { ... }
class ThreeInts::const_iterator : public std::iterator< std::random_access_iterator_tag, const int> { ... }
The problem seems to be that otherwise ThreeInts::const_iterator both has members named const_iterator and iterator (aka the constructors). Also making the iterator inherit from const_iterator is not const-correct as the const_iterator should only hold a pointer/similar to const data. STL containers also keep the two iterators separate.
In that code, it would probably be sufficient to instead of defining iterator classes, simply define
using iterator = int*;
using const_iterator = const int*;

comparing two different boost::iterator_facade iterators

I have two iterators, both derive from boost::iterator_facade (but not from each other) and I want to be able to compare them because I don't want to have more end() methods when one is sufficient. Is it possible?
The following minimal example is not working for me, but I think it should. What am I doing wrong?
#include <vector>
#include <iostream>
#include <boost/iterator/iterator_facade.hpp>
using namespace std;
typedef vector<int> val_type;
typedef vector<val_type> vec_type;
class myiterator
: public boost::iterator_facade<
myiterator
, val_type
, boost::forward_traversal_tag
>
{
private:
friend class boost::iterator_core_access;
friend class base_myiterator;
public:
explicit myiterator(vec_type::iterator _it)
: it(_it)
{}
myiterator(myiterator const& other)
: it(other.it)
{}
private:
void increment() { ++it; }
bool equal(myiterator const& other) const
{
return (it == other.it);
}
val_type& dereference() const { return *it; }
vec_type::iterator it;
};
class base_myiterator
: public boost::iterator_facade<
base_myiterator
, val_type
, boost::forward_traversal_tag
>
{
private:
friend class boost::iterator_core_access;
public:
explicit base_myiterator(vec_type::const_iterator _it, val_type _base)
: base(_base),
it(_it)
{
idx.resize(base.size());
}
base_myiterator(base_myiterator const& other)
: base(other.base),
it(other.it)
{
idx.resize(base.size());
}
private:
void increment()
{
++it;
for (size_t i=0; i<base.size(); ++i)
{
idx[i] = base[i] + (*it)[i];
}
}
bool equal(base_myiterator const& other) const
{
return (it == other.it);
}
bool equal(myiterator const& other) const
{
return (it == other.it);
}
val_type const& dereference() const
{
return idx;
}
val_type base;
vec_type::const_iterator it;
val_type idx;
};
struct Sample
{
vec_type vec;
myiterator begin()
{
return myiterator(vec.begin());
}
base_myiterator begin(val_type const& base)
{
return base_myiterator(vec.begin(), base);
}
myiterator end()
{
return myiterator(vec.end());
}
};
int main ()
{
Sample s;
val_type val;
val.push_back(1); val.push_back(0);
s.vec.push_back(val);
val.clear(); val.push_back(0); val.push_back(1);
s.vec.push_back(val);
val.clear(); val.push_back(-5); val.push_back(5);
//for (myiterator it=s.begin(); it!=s.end(); ++it)
for (base_myiterator it=s.begin(val); it!=s.end(); ++it)
{
cout << (*it)[0] << " " << (*it)[1] << endl;
}
}
boost::iterator_facade checks if two iterators are interoperable before instantiating the relation operators.
It uses boost::type_traits::is_convertible to check if it is legal to convert one type of iterator into the other type. Thus if you add a constructor base_myiterator(myiterator const& other) it will work. It will use the special equal overload you provided and not do any conversion (i.e. the additional copy constructor won't be used, it just needs to be there).
Furthermore, the base_myiterator seems to operate as some sort of const_iterator (val_type const& reference() const). In this case you should pass val_type const as template parameter Value to iterator_facade as described here.

Implementing an interface for an iterator

I'm writing a class which will iterate over a set of handles. Basically I'm working against a bunch of C functions which implement the following interface:
SomeHandle getFirst(ParentHandle);
SomeHandle getNext(SomeHandle);
Here is my iterator's interface and its partial implementation. I need an interface so that I can Mock this iterator for the purposes of TDD.
template<class HandleT>
class IHandleIterator
{
public:
virtual void operator++() = 0;
virtual const HandleT& operator*() const = 0;
};
template<class HandleT>
class HandleIterator : public IHandleIterator<HandleT>
{
public:
// used by something.end()
HandleIterator() : _isLast(true)
{
}
// updates _isLast when the end is reached
virtual void operator++()
{
}
virtual const HandleT& operator*() const
{
return _currentHandle;
}
protected:
HandleT _currentHandle;
bool _isLast;
};
What I want to do is add operator!= to the interface to test when I've reached the end of what I'm iterating over, as follows:
for(IHandleIterator i=something.begin(); i!=seomething.end(); i++)
{
*i;
}
However I can't figure out how to do this. Can anyone offer me suggestions?
If I can't find a solution involving operator!= then I'm wondering if this is a good approach:
class IHandleIterator
{
public:
virtual void operator++() = 0;
virtual const HandleT& operator*() const = 0;
virtual bool isLast const = 0;
};
for(IHandleIterator i=something.begin(); !i.isLast(); i++)
{
*i;
}
What do you think?

Is it possible for a base class to provide an iterator interface that derived classes implement?

I am porting this code from Visual C++ 6.0 (it also worked with an older GCC++) to Visual Studio 2010 C++. The code compiles but throws an exception.
I have an base class, CncMatchedQueryAtom. This class is used contain matches of different types of target atoms (this is a graph matching application) for 99% of the cases there is a one to one match between the query and the target. This is handled by the derived class, CncMatchedQueryAtomSimple. This class works great. The problem is that some query atoms match groups of atoms, this is handled by the class, CncMatchedQueryAtomGroup. This class contains a vector with the matched atoms. I want the iterator class defined within the base class to encapsulate the vector iterator in the derived class such that begin() returns the vector begin() and the end returns the vector's end().
The old version has problems on the end() at runtime because it does the conversion by:
return &*group.end();
Which is no longer allowed by Visual C++
So how can a base class specify an iterator that derived classes can implement? This doesn't seem very obvious to me, but I'm new to C++. Nor is it something that seasoned C++ developers that I work with know of either.
Basically, I want the base class to have methods that provide begin and end functions that the derived classes implement.
Here is the code:
class CncMatchedQueryAtom
{
protected:
int notBlockAllocated;
public:
int allocateIndividually() const
{
return notBlockAllocated;
}
const CncAtom *queryAtom;
CncAtom *queryAtomVolitile() const
{
return (CncAtom*)queryAtom;
}
// set when the class has been allocated by newing
// intialize all default constructors to be notBlockAllocated
CncMatchedQueryAtom()
: notBlockAllocated(1)
, queryAtom(NULL) // i don't think this needs to be initialized to null
{
}
CncMatchedQueryAtom(int noBlock)
: notBlockAllocated(noBlock)
, queryAtom(NULL) // i don't think this needs to be initialized to null
{
}
// may not need this now that it's a virtual!
CncMatchedQueryAtom(const CncMatchedQueryAtom &that)
: queryAtom(NULL)
{
*this = that;
}
// this needs to be virtual so when delete CncMatchedQueryAtom is called
// the virtual calss members are destructed too
virtual ~CncMatchedQueryAtom()
{
}
virtual void dump() const =0;
virtual void clearMapping() =0;
virtual CncMatchedQueryAtom *newCopy() const =0;
virtual void coverHits(class CncTarget *) const = 0;
// iterates over all matched target atoms for this query atom
class iterator
{
private:
CncMatchedTargetAtom *ptr;
public:
iterator()
{
}
iterator(const CncMatchedTargetAtom *targetAtom) // constructor from a target ptr
:ptr((CncMatchedTargetAtom *)targetAtom)
{
}
iterator(const iterator &oldOne)
:ptr(oldOne.ptr)
{
}
~iterator()
{
}
int operator==(const iterator &that) const
{
return ptr==that.ptr;
}
int operator!=(const iterator &that) const
{
return ptr!=that.ptr;
}
const CncMatchedTargetAtom &operator*() const
{
return *ptr;
}
iterator operator++(int NotUsed) // post increment
{
iterator returnValue(*this);
++ptr;
return returnValue;
}
iterator &operator++() // pre increment
{
++ptr;
return *this;
}
int operator<(const iterator &rhs) const
{
return (this->ptr < rhs.ptr);
}
CncMatchedTargetAtom *operator->()
{
return ptr;
}
};
virtual iterator begin() const =0;
virtual iterator end() const =0;
virtual int size() const = 0;
virtual double molecularWeight() const = 0;
const CncAtom *getFirstTargetAtom() const
{
return (*begin()).matchedTargetAtom;
}
CncAtom *getFirstTargetAtomVolitile() const
{
return (CncAtom*)getFirstTargetAtom();
}
}; // class CncMatchedQueryAtom
class CncMatchedQueryAtomSimple : public CncMatchedQueryAtom
{
public:
// we need a constructor here since this is allocated with blockAlloc
CncMatchedQueryAtomSimple()
: CncMatchedQueryAtom(0)
{
}
// we use simple.targetAtom as a temporary variable
// used to pass to matching functions
CncMatchedTargetAtom simple;
void clearIt()
{
queryAtom=NULL;
notBlockAllocated=0;
}
// if queryAtom is an element-type atom (or Lp or A atom)
void dump() const;
void clearMapping()
{
}
CncMatchedQueryAtom *newCopy() const
{
// since this is usually not allocatedIndividually I'll set
// the notBlockAllocatedFlag on the copy to be sure if this
// does happen it will individually deallocate it
CncMatchedQueryAtomSimple *retVal = new CncMatchedQueryAtomSimple(*this);
retVal->notBlockAllocated = 1;
return (CncMatchedQueryAtom *)retVal;
}
void coverHits(class CncTarget *) const;
iterator begin() const
{
return &simple;
}
iterator end() const
{
return &simple+1;
}
int size() const
{
return 1;
}
double molecularWeight() const
{
return CncMolGetAtomicMassAve(simple.matchedTargetAtom->getAtomicNumber());
}
}; // class CncMatchedQueryAtomSimple
class CncMatchedQueryAtomGroup : public CncMatchedQueryAtom
{
public:
// if queryAtom is an R- or X-group searching for
std::vector<CncMatchedTargetAtom> group;
void dump() const;
void clearMapping()
{
group.clear();
}
CncMatchedQueryAtom *newCopy() const
{
return new CncMatchedQueryAtomGroup(*this);
}
void coverHits(class CncTarget *) const;
iterator begin() const
{
return &*group.begin();
}
iterator end() const
{
// this is a hack, works with Visual C++ 6.0 and older GCC++ but not VS C++ 2010
return &*group.end(); // Throws error at runtime! Iterator Not Dereferencable
}
int size() const
{
return group.size();
}
double molecularWeight() const
{
double sum=0;
std::vector<CncMatchedTargetAtom>::const_iterator q;
for (q=group.begin()
; q!=group.end()
; ++q)
{
sum += CncMolGetAtomicMassAve(q->matchedTargetAtom->getAtomicNumber());
}
return sum;
}
}; // class CncMatchedQueryAtom
An example of how the iterator is called:
// Sample call to the iterator
// (*elem)->getMatchedAtom() returns a CncMatchedQueryAtom *
CncMatchedQueryAtom::iterator atomMatched;
// welp it looks like we have to do these
//(*elem)->getFirstTargetAtom
for (atomMatched=(*elem)->getMatchedAtom()->begin()
; atomMatched!=(*elem)->getMatchedAtom()->end() // Runtime exception here!
; ++atomMatched)
{
existenceFingerprint.setBit(
atomMatched->matchedTargetAtom->indexInStructure);
}
Thanks, hopefully this isn't too much code...
You cannot convert iterators from one container into iterators to another container.
It used to work with VC6, because they happened to use a pointer as vector::iterator. Later versions have an iterator class where the conversion does not work.