DISCLAIMER I’m not allowed to use BOOST or any other library, only standard.
In my class Foo I’ve a template function foo, which takes 2 parameters: a pointer-to-object and a pointer-to-this-object-member-function. The foo function works with pointer of any class, as you can see. I do NOT know, what class will be passed to it. This function creates an instance of a template structure.
template <typename TypeName>
struct Bar
{
void(TypeName::*action)();
TypeName* objPtr;
};
template <typename TypeName> void Foo::foo ( void(TypeName::*action)() , TypeName* objPtr )
{
Bar <TypeName> bar;
bar.action = action;
bar.objPtr = objPtr;
};
My question is: how do I store objects of Bar, created in foo, so I can iterate through them later and call the pointer-to-an-object-member-function like this:
(BarStorage[i].objPtr->*BarStorage[i].action)();
Use type erasure:
then simply call
myBars[x]->invoke();To answer questions in comments.
What’s up with
override? Explicitly say that you override virtual function from a base class. This is not really necessary here, but is considered good practice. For more details see Wikipedia article.Its a new feature from C++11, some compilers supported this feature in one way or another for a long time, but its been standardized only now. GCC should support this feature from version 4.7 – you have to use command line parameter
-std=c++0x.What’s up with
unique_ptr? It makes life easier. When you allocatenew Bar<XXX>(), you must at some point saydeleteto free that memory. If you put the pointer in a resource managing object likeunique_ptr, you no longer need to worry about deleting it. Withvector<BarBase*>you would have to declare a destructor inFoothat does something like:If you use
vector<unique_ptr<BarBase>>, you don’t need to worry about deleting anything. Whenvectoris destroyed at end ofFoo‘s life, it will destroy its elements – andunique_ptrdeletes the memory it contains in its own destructor.This is also C++11 feature – addition to standard library. You don’t have to use it (but then make sure to delete everything at the end).
What’s up with
auto? Instead of repeating the same type twice (Bar<Type> * bar = new Bar<Type>();), just use it once and let the compiler deduce the correct type of the variable based on the type of the initializer. It behaves exactly the same, its just less typing and looks better 🙂Also C++11 feature, supported in GCC since v4.4.
Why
myBars[x]->invoke()does the right thing? Becauseinvokeis declared virtual inBarBase. This means the method executed is chosen based on the dynamic type (the real type during execution) ofmyBars[x], not static type. For in-depth explanation, see Wiki. There is a minor run-time overhead with this mechanism, but it can’t be helped when dealing with dynamic types.