Right - rewrite here and much easier.
I agree with s3rius that you should still use std :: vector. Ideally, if you keep cats, you will use ...
std::vector<Cat>
and if you keep dogs, you would like ...
std::vector<Dog>
However, you need run-time polymorphism to choose which case you are dealing with.
One way (or inspired) by a strategy design pattern. Define a base class for your interface for these vectors and create a template class that implements this interface containing the vector.
class Animals_IF { public: virtual int size () const = 0; }; template<typename T> class Animals_Vector { private: std::vector<T> store; public: int size () const; }; template<typename T> int Animals_Vector<T>::size () const { return store.size (); }
The problem here is that the interface cannot mention Cat or Dog because it does not know the specific type, which, of course, is why I chose size as the approximate method above.
One solution is to pass values using boost::variant possible types, so each of the strategy / wrapper classes can verify that the values it receives are the correct type before using them. Wrapping / unfolding values in a variant can be processed using template methods in the base class (without a template).
In cases where all that wrapping and unpacking becomes ineffective, you must determine what case you are dealing with, and then call the correct type of strategy / shell (and not the base class). To do this, use boost :: variant of all strategy / shell cases. This does not prevent you from having a pointer to the base class. In fact, wrap both the pointer-base-class and boost::variant classes in the class (use template methods if necessary).
class Animals_IF { public: typedef boost::variant<Cat,Dog> Animal; virtual int size () const = 0; template<typename T> void slow_push (const T &p) { push_ (Animal (p)); } private: virtual void slow_push_ (const Animal &p) = 0; }; template<typename T> class Animals_Vector { public: int size () const; void fast_push (const T &p); private: std::vector<T> store; void slow_push_ (const Animal &p); }; template<typename T> int Animals_Vector<T>::size () const { return store.size (); } template<typename T> void Animals_Vector<T>::fast_push (const T &p) { store.push (p); } template<typename T> void Animals_Vector<T>::slow_push_ (const Animal &p) { const T* item = boost::get<T> (&p); if (T) store.push (*item);
If there is nothing that a common interface can provide (since each method must pass values, and packaging / expanding as options is unacceptable), the whole strategy is not needed. Just use boost :: variant for different types of std :: vector.
Also, the above fast_push won't be fast because push too easy to use - the idea is that this approach is faster for complex methods that can avoid re-checking the type of runtime by doing it once, front-end.
By the way - a good question.