I'm attempting to create a generic container type to provide a single common interface, as well as hide the internal containers I'm using as they are subject to change.
Basically I have plugins that return collections of items and I don't wish the plugins to be aware of the type of container my code is using.
Can anyone point me in a better direction then the example code below?
template<class C, typename I>
class Container
{
public:
//...
void push(const I& item)
{
if(typeid(C) == typeid(std::priority_queue<I>))
{
std::priority_queue<I>* container = (std::priority_queue<I>*)&_container;
container->push(item);
}
if(typeid(C) == typeid(std::list<I>))
{
std::list<I>* container = (std::list<I>*)&_container;
container->push_back(item);
}
else
{
//error!
}
};
private:
C _container;
//...
}
Thanks
I have plugins that return collections of items and I don't wish the plugins to be aware of the type of container my code is using.
Have your plugins provide begin and end iterators into their collections of items and then consume the range as you see fit.
The greatest advantage of iterators is that they allow complete decoupling of how the data is stored (the container) from how the data is used (the algorithm; in your case, your application code that consumes the plugin data).
This way, you don't have to care how the plugins store their data and the plugins don't have to care what you do with their data once they give it to you.
You know, when you wrote "common interface", I was sure you were going to show something Java style with an abstract class and subclasses that wrap standard containers. I was surprised to see a bunch of typeid calls...
But then, why do you want to do this? Most containers share a common interface, and with the power of SFINAE, you don't even have to write special code! Just use templates and call the method directly.
EDIT: Forgot that standard containers have no virtual methods and therefore, cannot be dynamic_casted.
Start with a class as above, expose minimal interface needed by your plugins. Then implement it in terms of the container you are going to use. This is called container adapter and it is how std::stack is implemented.
If you really need adapter for more then one STL container go with template, have a look at std::stack, it will show how to do that.
Don't switch on typeid, why would you want that?
BTW, go with what James suggests unless there is a need to expose container itself.
Related
As everyone knows: It's possbile to create linkes lists with C / C++ in order to make a program dynamical.
But now, I'm programming a "linked Class" in c++.
My Parent-Class "GAME" should have a variable number of Elements. And each Element is a class.
So I programmed this:
class GAME : public LEVEL
{ private:
ELEMENT *startPointer;
public:
GAME()
{ startPointer=NULL;
}
initGame()
{ p=aStartPointer;
while(p!=NULL);//This loop is based on a linked list, so its dynamic
{ startPointer=new ELEMENT(startPointer);
p=p->next;
}
}
}
class ELEMENT
{ private:
ELEMENT *next;
public:
ELEMENT(ELEMENT* nextPointer)
{ next=nextPointer;
}
}
My Problem: I never heard about a linked class before, and I'm not sure if I should use it.
Does professional programmers use such methods (and is it usefull?), or are there better Methods to do this?
are there better Methods to do this?
Yes. Here is one:
class GAME : public LEVEL
{ private:
std::vector<ELEMENT> elements;
...
};
Use the standard library containers:
Generally, use std::vector<>.
If you need uniqueness, use std::set<>
If you need to associate elements with keys, use std::map<>
If you need to insert or delete items from the container very often or very quickly, use std::list<> or std::set<>
There are other considerations. Consult a good book to learn how to effectively use standard containers.
Looks like you are trying to implement a linked list under a different name. A better design would be to use a list or vector as a member of your class to store the ELEMENTS instead of having it be the basic functionality of the GAME class.
This allows you to have a separation between container-like object and your application classes.
If what you're trying to do is create a container that can contain different types of object instances (ie, a non-homogeneous container), there're several approaches (which generally involve homogenizing the container). You can either set up a common base clase so that you can store handles-to-base. Another option is discriminated unions.
As the other posts mention, the container itself should probably be an STL container, unless you have a really good reason to use something else (and even then, the 'more standard', the better; homebrew is not a good idea unless it is for educational purposes only).
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.
I would like to write a "versatile" class representing the general container storing pointers. Should I use public inheritance or containment?
template <class T>
class List : public std::vector <T *>
{
//...
}
Or
template <class T>
class List
{
private:
std::vector <T *> items;
//...
}
May some problems occur with abstract classes (i.e. virtual destructor)?
If neither proposal is appropriate, what design should I follow (and could you include a short example)?
This is already done for you with Boost's pointer containers.
I do not like boost so I would like to use only C++ 0x00 standard :-).
— Ian (comment)
If you still want to re-invent these classes, look at the design decisions they made. In particular, they don't inherit from other containers as your first code does.
In fact, just copy the code right out from Boost. This is a header-only library and should be straight-forward (i.e. few implementation-specific workarounds). Boost's license is very liberal, not even requiring you to mention Boost when distributing compiled programs.
How about:
typedef std::vector<boost::shared_ptr<T> > List;
That is, I think it's better to use a resource managing pointer within regular container classes than to reinvent each of the container classes to add resource management capability.
private inheritance is a common tactic for creating classes that are implemented in terms of another. Code that uses the class can't tell that the derived class is derived from a private base, so you won't end up in the sorts of situations that might ordinarily require a virtual destructor.
Use using to import members from the private base to the derived class. For example:
template<class T>
class List:
private std::vector<T>
{
public:
using std::vector<T>::operator[];
using std::vector<T>::size;
};
This is a bit crude, but it gives you some flexibility. You can start out by using private inheritance, and this saves you some typing compared to writing forwarding functions, but you can still write alternative implementations long-hand as required. And then, if/when this becomes inappropriate, you can change the implementation style -- perhaps have a vector as a member, for example, or maybe do everything by hand -- safe in the knowledge that client code won't need to change.
This is ideal for situations where you're pretty sure you'll eventually need a non-standard type of container, but have an existing container type that mostly fits the bill for now. And it's a better medium-term solution than a typedef, because there's no risk of client code accidentally (or on purpose...) using the two types interchangeably.
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.
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.