Using Iterators to hide internal container and achieve generic operation over a base container
I basically want to have a base container class which can return a generic iterator that can be used to traverse an instance of the container class, without needing to specify iterator templates. I think I cannot implement the base container over a class template, which would then require a traversal algorithm based on template classes which are not known in advance. The base container can be inherited and implemented using any (custom or standard) container type/implementation within. Here are some code samples to make it clear:
struct MyObject {
int myInt;
}
// an abstract container
class BaseContainer {
public:
virtual void insertMyObject(MyObject& obj) = 0;
virtual iterator getFirst(); // the iterator type is for demonstration purposes only
virtual iterator getLast(); // the iterator type is for demonstration purposes only
}
// Sample container class that uses a std::vector instance to manage objects
class BaseContainer_Vector : public Base开发者_如何学编程Container {
public:
void insertMyObject(MyObject& obj); // e.g. just pushes back to the vector
iterator getFirst(); // needs to override the iterator?
iterator getLast(); // needs to override the iterator?
private:
std::vector<MyObject> objectContainer;
}
I will then have a list of container objects, and I want to iterate over both these containers and the objects stored.
std::vector<MyContainer*> containers;
for(int i=0 ; i<containers.size() ; i++){
iterator i = containers[i]->getFirst();
iterator iend = containers[i]->getLast();
for(; i != iend ; i++) {
std::cout << (*i).myInt << std::endl;
}
}
I further would like to have support for boost foreach macro statement. It supports extensions as long as range_begin and range_end functions are properly. But, the example in boost doc uses std::string::iterator as return type, while what I need is a generic iterator class and I could not yet figure out how to do that as well.
std::vector<MyContainer*> containers;
for(int i=0 ; i<containers.size() ; i++){
BOOST_FOREACH(MyObject obj, *(containers[i])) {
std::cout << obj.myInt << std::endl;
}
}
I think I can define my own iterator class, then each class that extends BaseContainer should define their own iterator extending that basic iterator. Yet, I would prefer to use standard iterators (stl or boost) to support this structure, rather that writing my own iterators. I guess this approach will work, but I am open to comments regarding its efficiency.
Is there a feasible approach that can solve this problem elegantly? Or am I missing a simple point which can solve this problem without any pain?
A similar question can be found here, but the proposed solutions seem a bit complex for my needs, and the requirements differ as far as I can understand.
It's gonna be complicated.
As already stated, first you need your iterators to have value semantic because since they are usually copied around otherwise it would result in object slicing.
class BaseContainer
{
protected:
class BaseIteratorImpl; // Abstract class, for the interface
public:
class iterator
{
public:
iterator(const BaseIteratorImpl& impl);
private:
BaseIteratorImpl* m_impl;
};
iterator begin();
iterator end();
}; // BaseContainer
Then, BaseIterator
forwards all methods to m_impl
.
This way you achieve value semantic syntax with a polymorphic core.
Obviously, you'll have to handle deep-copy semantics and proper destruction.
Some notes:
- publish both an
iterator
and aconst_iterator
class - name your methods
empty
,size
,begin
,end
etc... for compatibility with STL algorithms
You can check SGI Iterators for help about the Concepts and operations your operators should support for maximum compatibility.
精彩评论