In C++, should iterable types be non-polymorphic?
A bit of background:
I am currently working on an assignment from my OOP course which consists in designing and implementing a phone book manager around various design patterns.
In my project there are 3 classes around which all the action happens:
- Contact (the types stored in the phone book);
- ContactField (fields stored in the Contact).
ContactManager must provide a way to iterate over its contacts in 2 modes: unfiltered and filtered based on a predicate; Contact must provide a way to iterate over its fields.
How I initially decided to implement:
All design patterns books I came across recommend coding to an interface so my first thought was to extract an interface from each of the above classes and then make them implement it.
Now I also have to create some kind of polymorphic iterator for things to be smooth so I adapted the Java iterator interface to write forward iterators.
The major setback with this design is that I lose interoperability with stl <algorithm> and the syntactic sugar offered by range based for loops.
Another issue I came across is the Iterator<T>::remove() function. If I want an iterator that can alter the sequence it iterates over (remove elements) then all is fine however if I don't want that behavior I'm not exactly sure what to do.
I see that in Java one can throw UnsupportedOperationException which isn't that bad since (correct me if I'm wrong) if an exception isn't handled then the application is terminated and a stack trace is shown. In C++ you don't really have that luxury (unless you run with a debugger attached I think) and to be honest I'd rather prefer to catch such errors at compile time.
The easiest way out (that I see) of this mess is to avoid using interfaces on the iterable types in order to accommodate my own stl compatible iterators. This will increase coupling however I'm not sure it will actually have any impact in the long run (not in the sense that this project will become throw away code soon of course). My guess is that it won't however, I'd like to hear the elders opinion as well before I proceed with my design.
I would probably take a slightly different approach.
Firstly, iteration over a contact is pretty simple since it's a single type of iteration and you can just provide begin and end methods to allow iteration over the underlying fields.
For the iteration over a PhoneBook I would still just provide a normal begin and end, and then provide a for_each_if function that you use to iterate over only the contacts that are interesting, instead of trying to provide a super-custom iterator that skips over un-interesting elements.