Abstract wrapper for stl containers? - c++

I'd want to expose some objects as abstract containers with stl-style manipulation possibilities (for_each loops, iterators) and hide container implementation details.
Performance issues don't matter (virtual calls and even memory allocation while copying "universal" iterator is acceptable).
I'm going to write an abstract container interface with pure virtual functions (+ "universal" iterator over the container) and an implementaition adapter for stl sequential containers.
But maybe there are useful existing libraries for this purpose?
Or it's totally a bad idea?

Thomas Becker has some useful advice (type erasure). You may also find Stroustrup's SCARY paper useful.

If your "objects" aren't STL objects but custom ones, I think it's a good idea.
As you can see on http://www.sgi.com/tech/stl/Vector.html , vector "is a model of" RandomAccessContainer. Most Boost packages use similar concepts (the term realy is "concept")
In C++, you've got two possibilities to do this :
An abstract class (interface) as you suggested
Templates
With templates you can do something as :
doSomething < AnythingThatIsIterable >(AnythingThatIsIterable i){
for (AnythingThatIsIterable::itertaor it = i.begin(); it != i.end(); ++i){
it->foo()
}
}
Any class which provides an iterator, begin and end will work : std::vector, but also your own objects.
These objects don't have to inherit from any interface, so std::vector will work.

Here is my forward iterator wrapper for Java style implemented one. It's ugly. Boost parts are optional an might be refactored out.

The most generic solution to the problem of "exposing a C++ class in such a way that users of the class do not have to recompile their programs whenever my implementation of the class changes" is the pImpl pattern. For more info: http://en.wikipedia.org/wiki/Opaque_pointer

I understand the user's question completely. He/She wants a custom container class that exposes to the user an STL-like interface. The standard STL containers do not suffice in some manner and so they are not a suitable choice.
For example, I have an interface class for a 'Dataline' called IDataline. An implementation of the IDataLine interface takes at construction a delimited string, parses it and exposes the list of fields. via a const_iterator with forward_iterator_tag semantics.
No STL container can do this out of the box.
Furthermore, my client class wants to be able to iterate through two data line fields and compare them, field by field.
I have defined the IDataline interface as follows:
1 class IDataline
2 {
3 public:
4 class const_iterator
5 {
6 public:
7 virtual const_iterator& operator=(const const_iterator& rhs) =0;
8 virtual bool operator==(const const_iterator& rhs) =0;
9 virtual bool operator!=(const const_iterator& rhs) =0;
10 virtual const_iterator& operator++() =0;
11 virtual const_iterator operator++(int) =0;
12 virtual const Field& operator*() =0;
13 virtual const Field* operator->() =0;
14 virtual const Field& operator[](size_t idx) =0;
15 virtual size_t offset() =0;
16 };
17
18 virtual const_iterator begin() =0;
19 virtual const_iterator end() = 0;
20 };
The problem can be seen on lines 11, 18 and 19 - we need to be able to return a const_iterator, which requires a copy constructor, but since it is virtual, there is neither a default nor a copy constructor (for the interface type) and the compiler (properly) balks.
You might argue that I could define begin() and end() as:
virtual const_iterator& begin() = 0;
virtual const_iterator& end() = 0;
Then, I can create two instances of the specialized iterator in the specialized host and return references (or pointers for those who prefer those), to get this to work for my case.
The problem is that such an implementation does not meet all the requirements for forward iterators and will break in more general use cases that rely on forward iterator semantics.
There are two ways I've found after a bit of thought (and colleague consult) that this can be addressed:
Does your host class have to be completely abstract? If you can minimize the abstraction to just the behavior you need to vary, then your instantiable host can embed a concrete iterator (because an instance of the class itself can be instantiated) and you have what you need.
Eduardo Leon above indicates that the iterator itself can be wrapped using the pimpl (Pointer to an implementation) idiom. While there is a lot of material available that thoroughly describes that technique, Basilev, in comments below Leon's suggestion, indicates that he doesn't believe the pimpl idiom will work. My colleague offered to me a technique to try, so I will work up a tested sample. If it works, I'll share it. If not, I'll detail the experience gained in the sample and wait for someone more knowledgeable to weigh in on whether or not pimpl is applicable in this case.

Related

alternative to virtual typedef without templates

Edited Shorter Question:
When using a pointer to an abstract class, how can I call methods of the actual type of the object it points to?
I have an abstract BaseTree class with a public
virtual BaseTree const& operator[](NodeIndex const& poss) const = 0;
where NodeIndex is in practice std::vector<unsigned int>. I have also a TreeBasicIterator class which includes
public:
/// Access the tree to which m_tree points
BaseTree& operator*() const
{
//checking...
return (*m_tree)[*this];
}
private:
/// the tree the current iterator refers to
BaseTree* m_tree=nullptr;
Problem (I think it is the crux of my initial question below):
How can I use the methods of the class corresponding to the actual type of *m_tree? For now, when dereferencing my iterator, I can only use methods of the abstract class BaseTree.
I would like to avoid making TreeBasicIterator a template (see the initial question below).
Initial Question
As many (relatively new?) users of C++, I would like to write
virtual typedef something my_virtual_type;
inside classes definitions. Unfortunately it is not possible...
The most popular alternative seems to be templates, as for instance in alternative to virtual typedef which provides a nice sum up.
However I am not sure it covers everything a virtual typedef would. I present below a problem, for which I would like to have virtual typedefs. I have a (temporary?) working solution using overloading and not templates.
I want to create a fancy tree structure, including iterators.
1) I define a NodeIndex type, ancestor of my future iterators. (NodeIndex is in my case std::vector<unsigned int>, but it doesn't matter.)
2) I define an abstract BaseTree class, used in my iterators bellow. The class includes in particular virtual methods which returns NodeIndex indexes to move in the tree (e.g. NodeIndex begin()), and operator[](NodeIndex const&).
3) I define a TreeBasicIterator class, inheriting from NodeIndex, which for coherence purpose includes a const reference to a BaseTree, and implements various iterators methods (making use of the virtual methods provided by BaseTree).
(I have actually two classes: TreeBasicIterator, and Const_TreeBasicIterator with a const reference to a const BaseTree; I use preprocessor macros to mimic a template based on const-ness, but this is another problem.)
4) I have defined a TreeNode<T> template class (T is the node content), inheriting from BaseTree. For now its begin() method returns a NodeIndex, and its operator[] takes a NodeIndex as argument, and everything works fine.
5) However I want to include my TreeBasicIterator in my TreeNode class. I would like to include a
virtual typedef NodeIndex Iterator;
in my BaseTree class, and modify the virtual begin() method signature to Iterator begin().
Then TreeNode would include a
virtual typedef TreeBasicIterator Iterator;
its begin() method signature would be Iterator begin(),
and everything would be hopefully fine :)
6) I do not wish to use templates on TreeBasicIterator: it is now compiled once for all.
Making BaseTree a template would make TreeBasicIterator a template, and so loose a part of the benefits of the abstraction in BaseTree.
Instanciating BaseTree with NodeIndex as Iterator type would be superfluous: in practice nobody would inherit from that particular instance.
7) Prospective:
I will use trees with a fixed or rarely modified structure, but more frequently modified node contents, and even much more frequently read accesses. To optimize access, I intend to further derive from TreeNode a TreeVector class, which will include a sorted exhaustive std::vector of NodeIndex (or BasicTreeIterator?) indexes. The Iterator virtual type in TreeVector would be std::iterator.
8) Current (temporary?) partially working solution:
TreeNode defines (via a usual typedef) an Iterator type (my TreeBasicIterator class). It does not override an Iterator type from BaseTree, but it could.
BaseTree has a NodeIndex begin() const method, which is both un-hidden, and overloaded in TreeNode by a Iterator begin() const method. It is not overridden.
Similarly, I have a NodeIndex next_index(NodeIndex) const in BaseTree, which is both un-hidden, and overloaded in TreeNode by a Iterator next_index(Iterator) const method.
So, It does not seem to interest anyone... Anyway, here my working solution: mixing template and non template classes.
TreeBasicIterator remains a non-template class as explained in the question.
dynamic_cast is the tool to call tree class-specific methods on its BaseTree pointer. However it is not reasonnable to have to use it each time an iterator is dereferenced in the code.
I derive a template TreeIterator class:
template<class MyTree> class TreeIterator: public TreeBasicIterator
whose methods use dynamic_cast, for instance:
TreeIterator(BaseTree & tree): TreeBasicIterator(tree) {check_type();};
MyTree& operator*() const
{
return dynamic_cast<MyTree &>(TreeBasicIterator::operator*());
}
void check_type()
{
try
{
// uses the built-in checkings of dynamic_cast
if(m_tree!=nullptr) dynamic_cast<MyTree &>(*m_tree);
}
catch(std::exception &e)
{
m_tree=nullptr; // invalidates the iterator
throw e;
}
}
And the once-for-all compiled methods of TreeBasicIterator are called when what is done is independent of the real tree class used.

How to get an iterator over the return values of member function?

class A
{
public:
const B& GetB() const;
};
vector<A> manyA;
template<typename ConstBIter>
void foo(ConstBIter beginB, ConstBIter endB);
Whats the most elegant way to get a iterator over the Bs stored in A. Could get the pointers, store them in an array and use a boost::indirect_iterator. But there is certainly a better way?
Write your own iterator class. In C++, you are not limited to using only the iterator classes that are defined in the standard C++ library.
If your class meets the requirements for an iterator, as defined in the C++ standard, it can be used with the C++ library anywhere where any other iterator, that meets the same requirements, can be used.
Many large software libraries, in fact, declare and define their own iterators, for their own particular purposes.
Got the solution...
typedef boost::transform_iterator<boost::function<B&(A&)>, vector<A>::iterator> BIter;
BIter beginBIter(manyA.begin(), boost::mem_fn(&Layer::GetB));
BIter endBIter(manyA.end(), boost::mem_fn(&Layer::GetB));

Writing my own implementation of stl-like Iterator in C++

I'm currently trying to understand the intrinsics of iterators in various languages i.e. the way they are implemented.
For example, there is the following class exposing the list interface.
template<class T>
class List
{
public:
virtual void Insert( int beforeIndex, const T item ) throw( ListException ) =0 ;
virtual void Append( const T item ) =0;
virtual T Get( int position ) const throw( ListException ) =0;
virtual int GetLength() const =0;
virtual void Remove( int position ) throw( ListException ) =0;
virtual ~List() =0 {};
};
According to GoF, the best way to implement an iterator that can support different kinds of traversal is to create the base Iterator class (friend of List) with protected methods that can access List's members. The concrete implementations of Iterator will handle the job in different ways and access List's private and protected data through the base interface.
From here forth things are getting confusing. Say, I have class LinkedList and ArrayList, both derived from List, and there are also corresponding iterators, each of the classes returns. How can I implement LinkedListIterator? I'm absolutely out of ideas. And what kind of data can the base iterator class retrieve from the List (which is a mere interface, while the implementations of all the derived classes differ significantly) ?
STL doesn't really employ abstract base classes and virtual functions. Instead it is knowingly designed not to be OO (in the sense of GoF) and built entirely on templates, aiming for "compile-time polymorphism". Templates don't care about abstract interfaces. Things work as long as they have a sufficiently similar interface (e.g if you were to call Append push_back instead, more code expecting STL compliant containers would work for you, such as std::back_insert_iterator).
A STL compliant iterator would have to overload lots of operators to behave like a pointer (as far as possible, given the limitations of the container), including *, ->, ++, -- (if bidirectional - doubly linked), == and !=.
The C++ standard library does not use polymorphism and inheritance in its implementation of iterators; instead, it uses C++ template metaprogramming and the notion (but not formal syntax*) of "concepts".
Essentially, it will work if the interface for your iterator class adheres to some set of requirements. This set of requirements is called a "concept". There are several different iterator concepts (see this page for a list of all of them), and they are hierarchical. The basics of creating a compatible C++ iterator is to make your interface conform to the concept. For a simple iterator that goes only in the forward direction, this would require:
A typedef value_type for the value that results from dereferencing your iterator.
A typedef reference_type, which is the reference type for the corresponding value type.
A typedef pointer, which is a pointer type for the corresponding value type.
A typedef iterator_category, which needs to be one of input_iterator_tag, forward_iterator_tag, bidirectional_iterator_tag, or random_access_iterator_tag, depending on your traversal mechanism.
A typedef difference_type indicating the result of subtracting two different iterators.
A const value_type& operator*()const function for dereferencing the iterator.
A value_type& operator*() function if your iterator can be used to manipulate the value.
Increment (operator++() and operator++(int) functions) for seeking forward.
A difference function: difference_type operator-(const type_of_iterator&)
If you choose one of the more advanced iterator categories, you may also need to specify a decrement and plus operator in order to be able to seek backwards or to seek an arbitrary distance.
*The C++ standard library uses concepts so frequently in an informal way, that the C++ standards commitee sought to introduce a formal mechanism of declaring them in C++ (currently they exist only in documentation of the standard library, and not in any explicit code). However, persistent disagreements on the proposal led to it being scrapped for C++0x, although it will likely be reconsidered for the standard after that.

C++ class hierarchy for collection providing iterators

I'm currently working on a project in which I'd like to define a generic 'collection' interface that may be implemented in different ways. The collection interface should specify that the collection has methods that return iterators by value. Using classes that wrap pointers I came up with the following (greatly simplified):
Collection.h
class Collection
{
CollectionBase *d_base;
public:
Collection(CollectionBase *base);
Iterator begin() const;
};
inline Iterator Collection::begin() const
{
return d_base->begin();
}
CollectionBase.h
class CollectionBase
{
public:
virtual Iterator begin() const = 0;
virtual Iterator end() const = 0;
};
Iterator.h
class Iterator
{
IteratorBase *d_base;
public:
bool operator!=(Iterator const &other) const;
};
inline bool Iterator::operator!=(Iterator const &other) const
{
return d_base->operator!=(*other.d_base);
}
IteratorBase.h
class IteratorBase
{
public:
virtual bool operator!=(IteratorBase const &other) const = 0;
};
Using this design, different implementations of the collection derive from CollectionBase and can return their custom iterators by returning an Iterator that wraps some specific implementation of IteratorBase.
All is fine and dandy so far. I'm currently trying to figure out how to implement operator!= though. Iterator forwards the call to IteratorBase, but how should the operator be implemented there? One straightforward way would be to just cast the IteratorBase reference to the appropriate type in implementations of IteratorBase and then perform the specific comparison for the implementation of IteratorBase. This assumes that you will play nice and not pass two different types of iterators though.
Another way would be to perform some type of type checking that checks if the iterators are of the same type. I believe this check will have to be made at run-time though, and considering this is an iterator I'd rather not perform expensive run time type checking in operator!=.
Am I missing any nicer solutions here? Perhaps there are better alternative class designs (the current design is an adaptation from something I learned in a C++ course I'm taking)? How would you approach this?
Edit: To everyone pointing me to the STL containers: I am aware of their existence. I cannot use these in all cases however, since the amounts of data I need to process are often enormous. The idea here is to implement a simple container that uses the disk as storage instead of memory.
This is not the way you should be using C++. I strongly suggest you investigate the standard library container classes, such as std::vector and std::map, and the use of templates. Inheritance should always be the design tool of last resort.
Please do mimic the STL way of doing containers. That way, it would be possible to e.g. use <algorithm> with your containers.
If you want to use inheritance for your iterators, I would recommend you to use a different approach than STL's begin()/end().
Have a look on IEnumerator from .NET framework, for example. (MSDN documentation)
Your base classes can look like this:
class CollectionBase
{
// ...
virtual IteratorBase* createIterator() const = 0;
};
class IteratorBase
{
public:
virtual bool isEnd() const = 0;
virtual void next() const = 0;
};
// usage:
for (std::auto_ptr<IteratorBase> it = collection.createIterator(); !it->isEnd(); it->next)
{
// do something
}
If you want to stay with begin()/end(), you can use dynamic_cast to check that you have a right type:
class MyIteratorBaseImpl
{
public:
virtual bool operator!=(IteratorBase const &other) const
{
MyIteratorBaseImpl * other2 = dynamic_cast<MyIteratorBaseImpl*>(&other);
if (!other2)
return false; // other is not of our type
// now you can compare to other2
}
}
I can advice you add to iterator a virtual 'entiy-id' function, and in operator!= checks this->entity_id () and other.entity_id () (my example, 'position' function is such 'entity-id' function).

Returning an 'any kind of input iterator' instead of a vector::iterator or a list::iterator [duplicate]

This question already has answers here:
Generic iterator
(3 answers)
Closed 8 years ago.
Suppose I want to implement in C++ a data-structure to store oriented graphs. Arcs will be stored in Nodes thanks to STL containers. I'd like users to be able to iterate over the arcs of a node, in an STL-like way.
The issue I have is that I don't want to expose in the Node class (that will actually be an abstract base class) which STL container I will actually use in the concrete class. I therefore don't want to have my methods return std::list::iterator or std::vector::iterator...
I tried this:
class Arc;
typedef std::iterator<std::random_access_iterator_tag, Arc*> ArcIterator; // Wrong!
class Node {
public:
ArcIterator incomingArcsBegin() const {
return _incomingArcs.begin();
}
private:
std::vector<Arc*> _incomingArcs;
};
But this is not correct because a vector::const_iterator can't be used to create an ArcIterator. So what can be this ArcIterator?
I found this paper about Custom Iterators for the STL but it did not help. I must be a bit heavy today... ;)
Try this:
class Arc;
class Node {
private:
std::vector<Arc*> incoming_;
public:
typedef std::vector<Arc*>::iterator iterator;
iterator incoming_arcs_begin()
{ return incoming_.begin(); }
};
And use Node::iterator in the rest of the code. When/if you change the container, you have to change the typedef in a single place. (You could take this one step further with additional typedef for the storage, in this case vector.)
As for the const issue, either define vector's const_iterator to be your iterator, or define double iterator types (const and non-const version) as vector does.
Have a look at Adobe's any_iterator: this class uses a technique called type erase by which the underyling iterator type is hidden behind an abstract interface. Beware: the use of any_iterator incurs a runtime penalty due to virtual dispatching.
I want to think there should be a way to do this through straight STL, similar to what you are trying to do.
If not, you may want to look into using boost's iterator facades and adaptors where you can define your own iterators or adapt other objects into iterators.
To hide the fact that your iterators are based on std::vector<Arc*>::iterator you need an iterator class that delegates to std::vector<Arc*>::iterator. std::iterator does not do this.
If you look at the header files in your compiler's C++ standard library, you may find that std::iterator isn't very useful on its own, unless all you need is a class that defines typedefs for iterator_category, value_type, etc.
As Doug T. mentioned in his answer, the boost library has classes that make it easier to write iterators. In particular, boost::indirect_iterator might be helpful if you want your iterators to return an Arc when dereferenced instead of an Arc*.
Consider using the Visitor Pattern and inverting the relationship: instead of asking the graph structure for a container of data, you give the graph a functor and let the graph apply that functor to its data.
The visitor pattern is a commonly used pattern on graphs, check out boost's graph library documentation on visitors concepts.
If you really don't want the client's of that class to know that it uses a vector underneath, but still want them to be able to somehow iterate over it, you most likely will need to create a class that forwards all its methods to std::vector::iterator.
An alternative would be to templatize Node based on the type of container it should use underneath. Then the clients specifically know what type of container it is using because they told them to use it.
Personally I don't think it usually makes sense to encapsulate the vector away from the user, but still provide most (or even some) of its interface. Its too thin of an encapsulation layer to really provide any benefit.
I looked in the header file VECTOR.
vector<Arc*>::const_iterator
is a typedef for
allocator<Arc*>::const_pointer
Could that be your ArcIterator? Like:
typedef allocator<Arc*>::const_pointer ArcIterator;
You could templatize the Node class, and typedef both iterator and const_iterator in it.
For example:
class Arc {};
template<
template<class T, class U> class Container = std::vector,
class Allocator = std::allocator<Arc*>
>
class Node
{
public:
typedef typename Container<Arc*, Allocator>::iterator ArcIterator;
typedef typename Container<Arc*, Allocator>::Const_iterator constArcIterator;
constArcIterator incomingArcsBegin() const {
return _incomingArcs.begin();
}
ArcIterator incomingArcsBegin() {
return _incomingArcs.begin();
}
private:
Container<Arc*, Allocator> _incomingArcs;
};
I haven't tried this code, but it gives you the idea. However, you have to notice that using a ConstArcIterator will just disallow the modification of the pointer to the Arc, not the modification of the Arc itself (through non-const methods for example).
C++0x will allow you do this with automatic type determination.
In the new standard, this
for (vector::const_iterator itr = myvec.begin(); itr != myvec.end(); ++itr
can be replaced with this
for (auto itr = myvec.begin(); itr != myvec.end(); ++itr)
By the same token, you will be able to return whatever iterator is appropriate, and store it in an auto variable.
Until the new standard kicks in, you would have to either templatize your class, or provide an abstract interface to access the elements of your list/vector. For instance, you can do that by storing an iterator in member variable, and provide member functions, like begin() and next(). This, of course, would mean that only one loop at a time can safely iterate over your elements.
Well because std::vector is guaranteed to have contiguous storage, it should be perfect fine to do this:
class Arc;
typedef Arc* ArcIterator;
class Node {
public:
ArcIterator incomingArcsBegin() const {
return &_incomingArcs[0]
}
ArcIterator incomingArcsEnd() const {
return &_incomingArcs[_incomingArcs.size()]
}
private:
std::vector<Arc*> _incomingArcs;
};
Basically, pointers function enough like random access iterators that they are a sufficient replacement.