C++: Designing the interface of a class containing many containers - c++

I couldn't find anything relevant, but sorry if this has been asked already. I sometimes find myself in a sitution in which I have a class, that contains internally say two different containers. Something like the following:
class Foo
{
public:
typedef std::vector<int> int_list;
typedef std::vector<X> x_list;
// It would be nice if the user could iterate through these etc. so that I
// could define functions that operate on them as non-member non-friends.
typedef int_list::size_type int_list_size_type;
typedef int_list::const_iterator int_list_const_iter;
typedef x_list::size_type x_list_size_type;
typedef x_list::const_iterator x_list_const_iter;
int_list_const_iter int_list begin() const { return ints_.begin(); }
x_list_const_iter begin() const { return xs_.begin(); }
int_list::size_type size_of_ints() const { return ints_.size(); }
x_list::size_type size_of_xs() const { return xs_.size(); }
// And so forth ... !
private:
int_list ints_;
x_list xs_;
};
Somehow I feel uneasy. Is this is a smart way of doing what I'm doing? Basically, for every container I would need typedefs and (const overloaded) begin and end methods etc. I'm curious: what would be your way of designing the interface, naming the typedefs etc? I guess I'm basically worried about the interface and the explosion of methods, and it looks kinda ugly too.
Maybe one way of limiting the number of begin/end methods would be a template-based approach using somekind of tags, but I'm not sure if that's sensible.
Thanks!

It sounds like your class is doing too much. If your clients need to do all those kinds of operations on those containers, it's probably best if you just expose a constant reference to the container itself instead of trying to wrap every STL interface yourself.
On the other hand, if your clients need to do all those things it's probably a sign that the class needs to be broken apart into smaller classes.

Have you actually tried this? You code won't compile. You can't have two functions with the same name/param list that return different things.
As to the intent...your misgivings are appropriate and your class is probably not doing enough of its own work to warrant its existence. The very fact that you want to expose the complete internals of the object so clients can work on them make me conclude that your class is almost certainly 100% useless. It's a design issue and your misgivings are simply your nose telling you something stinks.

You should not allow access to the containers. You should export the functionality of the class, and the class should have a central point. Assuming the class is using the containers, e.g. int is a key that references X, you will probably need an interface that coordinates access. In this case you should not provide access to the underlying containers.

Related

OOP design - Process an entire sequence of Foo objects

I'm new to objected-oriented design and I was hoping I could get some advice regarding a better way to design this project.
I have started with a FooSequence class which should initialize and store a sequence of Foo objects in a vector. I would like to be able to modify and delete the Foo objects from this sequence. That is, apply a number of algorithms to process the entire sequence of Foos, and delete poor-quality Foos from this sequence.
I'm not sure how I should interface FooSequence with a class that processes the Foo objects. If anyone could elaborate on relevant design patterns and pitfalls, I would greatly appreciate it.
I suppose I could:
a) Expand the scope of FooSequence and rename to something like FooProcessor where the member functions of FooProcessor will process member vSequence_
b) Provide accessor and mutator functions to allow read-write access to Foo objects. Use another class (FooProcessor) to modify and delete Foo objects from FooSequence. I'm not sure how this should be interfaced.
//A simplified header of the FooSequence class
class FooSequence {
public:
FooSequence(const std::string &sequence_directory);
~FooSequence();
//To process the sequence, another class must know the capacity of the vector
//I'm not sure if interfacing to std::vector member functions makes much sense
std::size_t getSize() const { return vSequence_.size(); }
//Should I use an accessor that returns a non-const reference??
//In this case, Why not just make the vector public?
std::vector<std::shared_ptr<Foo>> getFoo;
//Return a non-const reference to individual Foo in the sequence??
//This doesn't help iterate over the sequence unless size of vector is known
std::shared_ptr<Foo>& operator[] (std::size_t index) {
return vSequence_[index];
}
private:
const std::string directory_;
std::vector<std::shared_ptr<Foo>> vSequence_;
FooSequence(const FooSequence &);
void operator=(const FooSequence &);
};
I've tried consulting Design Patterns by the GoF but I think it is too advanced for me just yet. Any advice would be tremendously appreciated.
Edit: While I think this question should have a general answer regarding object-oriented design, I thought I should clarify that I am looking to interface an ImageSequence class with OpenCV. I am wondering about which strategies or designs I can use to best interface ImageSequence with other classes
Depending on what kind of processing you need to do on your Foo objects, I believe a simple approach of just having an std::vector<std::shared_ptr<Foo>> in conjunction with standard algorithm calls from the STL could be enough.
There is a lot you can do with the STL:
Sort
Transform
Find
Rearrange
etc...
And all these algorithms are available to you for use on std::vector because the standard containers and algorithms are designed to work together.
Have a look at the list of algorithms from cppreference:
STL alrogithm reference
General Design Guidelines (in response to your edit)
Keep it simple. The simpler your design is, the easier it will be to maintain your program. If your sequence of images can be represented as a simple vector, do it. You can then have other functions/classes operate on that vector by iterating over the images and processing them.
A simple ranged for works here:
for (auto& myImage: myImageVector) {
// Process my image here
}
for_each is a construct which allows you to apply a custom function to each element in the container.
For example in your case:
myCustomFunction ( Foo& fooObj)
{
//do something with the foo object
}
now you can call
for_each(vSequence_.begin(),vSequence_.end(),myCustomFunction)
This statement will execute myCustomFunction for each element in the sequence.
This is not a design advice per say , but in the context of your point a , A FooProcessor can use for_each whenever batch processing is required on all the objects.
i doubt, that you need that class at all.
in real life, you'd have a vector<Mat> (not a vector<shared_ptr<Mat>> , since Mat already acts as a smartpointer) and call it a day.

Interface-based programming in C++ in combination with iterators. How too keep this simple?

In my developments I am slowly moving from an object-oriented approach to interface-based-programming approach. More precisely:
in the past I was already satisfied if I could group logic in a class
now I tend to put more logic behind an interface and let a factory create the implementation
A simple example clarifies this.
In the past I wrote these classes:
Library
Book
Now I write these classes:
ILibrary
Library
LibraryFactory
IBook
Book
BookFactory
This approach allows me to easily implement mocking classes for each of my interfaces, and to switch between old, slower implementations and new, faster implementations, and compare them both within the same application.
For most cases this works very good, but it becomes a problem if I want to use iterators to loop over collections.
Suppose my Library has a collection of books and I want to iterator over them. In the past this wasn't a problem: Library::begin() and Library::end() returned an iterator (Library::iterator) on which I could easily write a loop, like this:
for (Library::iterator it=myLibrary.begin();it!=mylibrary.end();++it) ...
Problem is that in the interface-based approach, there is no guarantee that different implementations of ILibrary use the same kind of iterator. If e.g. OldLibrary and NewLibrary both inherit from ILibrary, then:
OldLibrary could use an std::vector to store its books, and return std::vector::const_iterator in its begin and end methods
NewLibrary could use an std::list to store its books, and return std::list::const_iterator in its begin and end methods
Requiring both ILibrary implementations to return the same kind of iterator isn't a solution either, since in practice the increment operation (++it) needs to be implemented differently in both implementations.
This means that in practice I have to make the iterator an interface as well, meaning that application can't put the iterator on the stack (typical C++ slicing problem).
I could solve this problem by wrapping the iterator-interface within a non-interface class, but this seems a quite complex solution for what I try to obtian.
Are there better ways to handle this problem?
EDIT:
Some clarifications after remarks made by Martin.
Suppose I have a class that returns all books sorted on popularity: LibraryBookFinder.
It has begin() and end() methods that return a LibraryBookFinder::const_iterator which refers to a book.
To replace my old implementation with a brand new one, I want to put the old LibraryBookFinder behind an interface ILibraryBookFinder, and rename the old implementation to OldSlowLibraryBookFinder.
Then my new (blistering fast) implementation called VeryFastCachingLibraryBookFinder can inherit from ILibraryBookFinder. This is where the iterator problem comes from.
Next step could be to hide the interface behind a factory, where I can ask the factory "give me a 'finder' that is very good at returning books according popularity, or according title, or author, .... You end up with code like this:
ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_POPULARITY);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...
or if I want to use another criteria:
ILibraryBookFinder *myFinder = LibraryBookFinderFactory (FINDER_AUTHOR);
for (ILibraryBookFinder::const_iterator it=myFinder->begin();it!=myFinder.end();++it) ...
The argument of LibraryBookFinderFactory may be determined by an external factor: a configuration setting, a command line option, a selection in a dialog, ... And every implementation has its own kind of optimizations (e.g. the author of a book doesn't change so this can be a quite static cache; the popularity can change daily which may imply a totally different data structure).
You are mixing metaphors here.
If a library is a container then it needs its own iterator it can't re-use an iterator of a member. Thus you would wrap the member iterator in an implementation of ILibraryIterator.
But strictly speaking a Library is not a container it is a library.
Thus the methods on a library are actions (think verbs here) that you can perform on a library. A library may contain a container but strictly speaking it is not a container and thus should not be exposing begin() and end().
So if you want to perform an action on the books you should ask the library to perform the action (by providing the functor). The concept of a class is that it is self contained. User should not be using getter to get stuff about the object and then put stuff back the object should know how to perform the action on itself (this is why I hate getters/setters as they break encapsulation).
class ILibrary
{
public:
IBook const& getBook(Index i) const;
template<R,A>
R checkBooks(A const& librarianAction);
};
If your libraries hold a lot of books, you should consider putting your "aggregate" functions into your collections and pass in the action want it to be perform.
Something in the nature of:
class ILibrary
{
public:
virtual ~Ilibrary();
virtual void for_each( boost::function1<void, IBook> func ) = 0;
};
LibraryImpl::for_each( boost::function1<void, IBook> func )
{
std::for_each( myImplCollection.begin(), myImplCollection.end(), func );
}
Although probably not exactly like that because you may need to deal with using shared_ptr, constness etc.
For this purpose (or in general in implementations where I make heavy use of interfaces), I have also created an interface for an iterator and other objects return this. It becomes pretty Java-a-like.
If you care about having the iterator in most cases of the stack: Your problem is of course that you don't really know the size of the iterator at compile time so you cannot allocate a stack variable of the correct size. But if you really care a lot about this: Maybe you could write some wrapper which either allocates a specific size on the stack (e.g. 128 bytes) and if the new iterator fits in, it moves it there (be sure that your iterator has a proper interface to allow this in a clean way). Or you could use alloca(). E.g. your iterator interface could be like:
struct IIterator {
// iterator stuff here
// ---
// now for the handling on the stack
virtual size_t size() = 0; // must return own size
virtual void copyTo(IIterator* pt) = 0;
};
and your wrapper:
struct IteratorWrapper {
IIterator* pt;
IteratorWrapper(IIterator* i) {
pt = alloca(i->size());
i->copyTo(pt);
}
// ...
};
Or so.
Another way, if in theory it would be always clear at compile time (not sure if that holds true for you; it is a clear restriction): Use functors everywhere. This has many other disadvantages (mainly having all real code in header files) but you will have really fast code. Example:
template<typename T>
do_sth_with_library(T& library) {
for(typename T::iterator i = library.begin(); i != library.end(); ++i)
// ...
}
But the code can become pretty ugly if you do rely too heavy on this.
Another nice solution (making the code more functional -- implementing a for_each interface) was provided by CashCow.
With current C++, this could make the code also a bit complicated/ugly to use though. With the upcoming C++0x and lambda functions, this solution can become much more clean.

Member functions for derived information in a class

While designing an interface for a class I normally get caught in two minds whether should I provide member functions which can be calculated / derived by using combinations of other member functions. For example:
class DocContainer
{
public:
Doc* getDoc(int index) const;
bool isDocSelected(Doc*) const;
int getDocCount() const;
//Should this method be here???
//This method returns the selected documents in the contrainer (in selectedDocs_out)
void getSelectedDocs(std::vector<Doc*>& selectedDocs_out) const;
};
Should I provide this as a class member function or probably a namespace where I can define this method? Which one is preferred?
In general, you should probably prefer free functions. Think about it from an OOP perspective.
If the function does not need access to any private members, then why should it be given access to them? That's not good for encapsulation. It means more code that may potentially fail when the internals of the class is modified.
It also limits the possible amount of code reuse.
If you wrote the function as something like this:
template <typename T>
bool getSelectedDocs(T& container, std::vector<Doc*>&);
Then the same implementation of getSelectedDocs will work for any class that exposes the required functions, not just your DocContainer.
Of course, if you don't like templates, an interface could be used, and then it'd still work for any class that implemented this interface.
On the other hand, if it is a member function, then it'll only work for this particular class (and possibly derived classes).
The C++ standard library follows the same approach. Consider std::find, for example, which is made a free function for this precise reason. It doesn't need to know the internals of the class it's searching in. It just needs some implementation that fulfills its requirements. Which means that the same find() implementation can work on any container, in the standard library or elsewhere.
Scott Meyers argues for the same thing.
If you don't like it cluttering up your main namespace, you can of course put it into a separate namespace with functionality for this particular class.
I think its fine to have getSelectedDocs as a member function. It's a perfectly reasonable operation for a DocContainer, so makes sense as a member. Member functions should be there to make the class useful. They don't need to satisfy some sort of minimality requirement.
One disadvantage to moving it outside the class is that people will have to look in two places when the try to figure out how to use a DocContainer: they need to look in the class and also in the utility namespace.
The STL has basically aimed for small interfaces, so in your case, if and only if getSelectedDocs can be implemented more efficiently than a combination of isDocSelected and getDoc it would be implemented as a member function.
This technique may not be applicable anywhere but it's a good rule of thumbs to prevent clutter in interfaces.
I agree with the answers from Konrad and jalf. Unless there is a significant benefit from having "getSelectedDocs" then it clutters the interface of DocContainer.
Adding this member triggers my smelly code sensor. DocContainer is obviously a container so why not use iterators to scan over individual documents?
class DocContainer
{
public:
iterator begin ();
iterator end ();
// ...
bool isDocSelected (Doc *) const;
};
Then, use a functor that creates the vector of documents as it needs to:
typedef std::vector <Doc*> DocVector;
class IsDocSelected {
public:
IsDocSelected (DocContainer const & docs, DocVector & results)
: docs (docs)
, results (results)
{}
void operator()(Doc & doc) const
{
if (docs.isDocSelected (&doc))
{
results.push_back (&doc);
}
}
private:
DocContainer const & docs;
DocVector & results;
};
void foo (DocContainer & docs)
{
DocVector results;
std :: for_each (docs.begin ()
, docs.end ()
, IsDocSelected (docs, results));
}
This is a bit more verbose (at least until we have lambdas), but an advantage to this kind of approach is that the specific type of filtering is not coupled with the DocContainer class. In the future, if you need a new list of documents that are "NotSelected" there is no need to change the interface to DocContainer, you just write a new "IsDocNotSelected" class.
The answer is proabably "it depends"...
If the class is part of a public interface to a library that will be used by many different callers then there's a good argument for providing a multitude of functionality to make it easy to use, including some duplication and/or crossover. However, if the class is only being used by a single upstream caller then it probably doesn't make sense to provide multiple ways to achieve the same thing. Remember that all the code in the interface has to be tested and documented, so there is always a cost to adding that one last bit of functionality.
I think this is perfectly valid if the method:
fits in the class responsibilities
is not too specific to a small part of the class clients (like at least 20%)
This is especially true if the method contains complex logic/computation that would be more expensive to maintain in many places than only in the class.

How do I return an std::set with a private comparator

I'd like to write a (C++) method that returns an std::set of custom objects. I do not however want to expose the comparator used when inserting the objects, so I make it a private class.
I create the set like this:
std::set<some_class, some_class_comparator> return_object;
now I want to return the set, so it has to be cast like this (implicitly when returning):
(const std::set<some_class>) return_object;
This is where the compiler complains. Is there a way to cast a mutable set with a comparator to an immutable without?
thanks a lot,
holger
Is there a way to cast a mutable set
with a comparator to an immutable
without?
No because
std::set<some_class, some_class_comparator>
and
std::set<some_class>
are different, unrelated types entirely. Templates are just that, templates -- a way of specifying how a type is to be generated before compilation. In the second case, the comparator is the default comparer that a std::set would come with.
Is there a compelling reason that some_class_comparotor needs to be private? Could it be its own stand-alone entity? Is it just you don't want to pollute the public interface of your class?
I don't think so. AFAIK std::set<some_class> is just shorthand for std::set<some_class, std::less<some_class> > so the set can't be converted as you want.
I suggest transferring the items into some other data structure (e.g. a vector) that will maintain keep the current items in an order without needing a comparator.
Your best solution is something like this:
class MyClass
{
class some_class_comparator;
public:
typedef std::set<int, some_class_comparator> ReturnSet;
ReturnSet myMethod();
// ...
private:
class some_class_comparator
{
public:
bool operator< (MyClass& m) {return true;}
};
};
//later...
MyClass::ReturnSet s = my_class_instance.myMethod();
This is two different types std::< Type, Comparator > and std::set< Type, DefaultComparator >.
You want to hide an implementation detail from the caller, that doesn't sound like a template, that sounds like virtual functions. I think first, you need to ask yourself, does this really matter? If so, hide your class behind an IOpaqueSet interface. Of course, then no other STL operations could work on it.
The STL comes with a lot of built-in classes, but it's also an extensible framework. If you define your::own::immutable_set, with iterators defined, other STL algorithms can use it. immutable_set<T> would be defined as a thin const wrapper around a mutable std::set<T, comparator<T> > (some template magic required to support different comparators, as they lead to different types). immutable_set<T>::iterator::operator++ would forward to std::set<T>::iterator::operator++, etc.

C++ alternatives to void* pointers (that isn't templates)

It looks like I had a fundamental misunderstanding about C++ :<
I like the polymorphic container solution. Thank you SO, for bringing that to my attention :)
So, we have a need to create a relatively generic container type object. It also happens to encapsulate some business related logic. However, we need to store essentially arbitrary data in this container - everything from primitive data types to complex classes.
Thus, one would immediately jump to the idea of a template class and be done with it. However, I have noticed C++ polymorphism and templates do not play well together. Being that there is some complex logic that we are going to have to work, I would rather just stick with either templates OR polymorphism, and not try to fight C++ by making it do both.
Finally, given that I want to do one or the other, I would prefer polymorphism. I find it much easier to represent constraints like "this container contains Comparable types" - a la java.
Bringing me to the topic of question: At the most abstract, I imagine that I could have a "Container" pure virtual interface that has something akin to "push(void* data) and pop(void* data)" (for the record, I am not actually trying to implement a stack).
However, I don't really like void* at the top level, not to mention the signature is going to change every time I want to add a constraint to the type of data a concrete container can work with.
Summarizing: We have relatively complex containers that have various ways to retrieve elements. We want to be able to vary the constraints on the elements that can go into the containers. Elements should work with multiple kinds of containers (so long as they meet the constraints of that particular container).
Edit: I should also mention that the containers themselves need to be polymorphic. That is my primary reason for not wanting to use templated C++.
So - should I drop my love for Java type interfaces and go with templates? Should I use void* and statically cast everything? Or should I go with an empty class definition "Element" that declares nothing and use that as my top level class in the "Element" hierarchy?
One of the reasons why I love stack overflow is that many of the responses provide some interesting insight on other approaches that I hadn't not have even considered. So thank you in advance for your insights and comments.
You can look at using a standard container of boost::any if you are storing truly arbitrary data into the container.
It sounds more like you would rather have something like a boost::ptr_container where anything that can be stored in the container has to derive from some base type, and the container itself can only give you reference's to the base type.
The simple thing is to define an abstract base class called Container, and subclass it for each kind of item you may wish to store. Then you can use any standard collection class (std::vector, std::list, etc.) to store pointers to Container. Keep in mind, that since you would be storing pointers, you would have to handle their allocation/deallocation.
However, the fact that you need a single collection to store objects of such wildly different types is an indication that something may be wrong with the design of your application. It may be better to revisit the business logic before you implement this super-generic container.
Polymorphism and templates do play very well together, if you use them correctly.
Anyway, I understand that you want to store only one type of objects in each container instance. If so, use templates. This will prevent you from storing the wrong object type by mistake.
As for container interfaces: Depending on your design, maybe you'll be able to make them templated, too, and then they'll have methods like void push(T* new_element). Think of what you'll know about the object when you want to add it to a container (of an unknown type). Where will the object come from in the first place? A function that returns void*? Do you know that it'll be Comparable? At least, if all stored object classes are defined in your code, you can make them all inherit from a common ancestor, say, Storable, and use Storable* instead of void*.
Now if you see that objects will always be added to a container by a method like void push(Storable* new_element), then really there will be no added value in making the container a template. But then you'll know it should store Storables.
Can you not have a root Container class that contains elements:
template <typename T>
class Container
{
public:
// You'll likely want to use shared_ptr<T> instead.
virtual void push(T *element) = 0;
virtual T *pop() = 0;
virtual void InvokeSomeMethodOnAllItems() = 0;
};
template <typename T>
class List : public Container<T>
{
iterator begin();
iterator end();
public:
virtual void push(T *element) {...}
virtual T* pop() { ... }
virtual void InvokeSomeMethodOnAllItems()
{
for(iterator currItem = begin(); currItem != end(); ++currItem)
{
T* item = *currItem;
item->SomeMethod();
}
}
};
These containers can then be passed around polymorphically:
class Item
{
public:
virtual void SomeMethod() = 0;
};
class ConcreteItem
{
public:
virtual void SomeMethod()
{
// Do something
}
};
void AddItemToContainer(Container<Item> &container, Item *item)
{
container.push(item);
}
...
List<Item> listInstance;
AddItemToContainer(listInstance, new ConcreteItem());
listInstance.InvokeSomeMethodOnAllItems();
This gives you the Container interface in a type-safe generic way.
If you want to add constraints to the type of elements that can be contained, you can do something like this:
class Item
{
public:
virtual void SomeMethod() = 0;
typedef int CanBeContainedInList;
};
template <typename T>
class List : public Container<T>
{
typedef typename T::CanBeContainedInList ListGuard;
// ... as before
};
First, of all, templates and polymorphism are orthogonal concepts and they do play well together. Next, why do you want a specific data structure? What about the STL or boost data structures (specifically pointer containter) doesn't work for you.
Given your question, it sounds like you would be misusing inheritance in your situation. It's possible to create "constraints" on what goes in your containers, especially if you are using templates. Those constraints can go beyond what your compiler and linker will give you. It's actually more awkward to that sort of thing with inheritance and errors are more likely left for run time.
Using polymorphism, you are basically left with a base class for the container, and derived classes for the data types. The base class/derived classes can have as many virtual functions as you need, in both directions.
Of course, this would mean that you would need to wrap the primitive data types in derived classes as well. If you would reconsider the use of templates overall, this is where I would use the templates. Make one derived class from the base which is a template, and use that for the primitive data types (and others where you don't need any more functionality than is provided by the template).
Don't forget that you might make your life easier by typedefs for each of the templated types -- especially if you later need to turn one of them into a class.
You might also want to check out The Boost Concept Check Library (BCCL) which is designed to provide constraints on the template parameters of templated classes, your containers in this case.
And just to reiterate what others have said, I've never had a problem mixing polymorphism and templates, and I've done some fairly complex stuff with them.
You could not have to give up Java-like interfaces and use templates as well. Josh's suggestion of a generic base template Container would certainly allow you do polymorphically pass Containers and their children around, but additionally you could certainly implement interfaces as abstract classes to be the contained items. There's no reason you couldn't create an abstract IComparable class as you suggested, such that you could have a polymorphic function as follows:
class Whatever
{
void MyPolymorphicMethod(Container<IComparable*> &listOfComparables);
}
This method can now take any child of Container that contains any class implementing IComparable, so it would be extremely flexible.