I want to fill a map with class name and method, a unique identifier and a pointer to the method.
typedef std::map<std::string, std::string, std::string, int> actions_type;
typedef actions_type::iterator actions_iterator;
actions_type actions;
actions.insert(make_pair(class_name, attribute_name, identifier, method_pointer));
//after which I want call the appropriate method in the loop
while (the_app_is_running)
{
std::string requested_class = get_requested_class();
std::string requested_method = get_requested_method();
//determine class
for(actions_iterator ita = actions.begin(); ita != actions.end(); ++ita)
{
if (ita->first == requested_class && ita->second == requested_method)
{
//class and method match
//create a new class instance
//call method
}
}
}
If the method is static then a simple pointer is enough and the problem is simple, but I want to dynamically create the object so I need to store a pointer to class and an offset for the method and I don't know if this works (if the offset is always the same etc).
The problem is that C++ lacks reflection, the equivalent code in a interpreted language with reflection should look like this (example in PHP):
$actions = array
(
"first_identifier" => array("Class1","method1"),
"second_identifier" => array("Class2","method2"),
"third_identifier" => array("Class3","method3")
);
while ($the_app_is_running)
{
$id = get_identifier();
foreach($actions as $identifier => $action)
{
if ($id == $identifier)
{
$className = $action[0];
$methodName = $action[1];
$object = new $className() ;
$method = new ReflectionMethod($className , $methodName);
$method -> invoke($object);
}
}
}
PS: Yes I'm trying to make a (web) MVC front controller in C++. I know I know why don't use PHP, Ruby, Python (insert your favorite web language here) etc?, I just want C++.
If you do not want to use member function pointers, you can use statics which take an argument of the class instance. For example:
This requires more work on the coder and causes maintainability issues (since if you update the signature of one, you must update that of the other as well).
You could also use a single static function which calls all your member functions:
Go for Subject-Observer design pattern.
I think the most important thing to find out here is, do all of your methods have the same signature? If they do, this is a trivial use of boost bind(if you're into that), functors are an option(the static, duck type kind), or just plain ole virtual inheritance is an option. Inheritance isnt currently in vogue but its pretty easy to understand and I dont think it complicates things anymore then using boost bind(imho best for small non systemic functors).
here is a sample implementation
I wrote that stuff last hours, and added it to my collection of useful stuff. The most difficult thing is to cope with the factory function, if the types you want to create are not related in any way. I used a
boost::variant
for this. You have to give it a set of types you ever want to use. Then it will keep track what is the current "active" type in the variant. (boost::variant is a so-called discriminated union). The second problem is how you store your function pointers. The problem is that a pointer to a member ofA
can't be stored to a pointer to a member ofB
. Those types are incompatible. To solve this, i store the function pointers in an object that overloads itsoperator()
and takes a boost::variant:Of course, all your types' functions have to have the same return type. Otherwise the whole game would only make little sense. Now the code:
It uses pretty fun techniques from boost preprocessor, function types and bind library. Might loop complicated, but if you get the keys in that code, it's not much to grasp anymore. If you want to change the parameter count, you just have to tweak variant_call_type:
Now you can call member functions that take an int. Here is how the call side would look:
Have fun!
If you now say the above is too complicated, i have to agree with you. It is complicated because C++ is not really made for such dynamic use. If you can have your methods grouped and implemented in each object you want create, you can use pure virtual functions. Alternatively, you could throw some exception (like std::runtime_error) in the default implementation, so derived classes do not need to implement everything:
For creating objects, a usual factory will do
The map could be composed by a map mapping IDs to a pair of class and function name (the same like above), and a map mapping that to a boost::function:
Calling the function would work like this:
Of course, with this approach, you loose flexibility and (possibly, haven't profiled) efficiency, but you greatly simplify your design.
Like many C++ questions, this looks like another application of Boost. You basically want to store the result of boost::bind(&Class::member, &Object). [edit] Storing such a result is easy with boost::function.
Perhaps you're looking for member function pointers.
Basic usage:
As stated in the C++ FAQ Lite, macros and
typedef
s would greatly increase readability when using member function pointers (because their syntax isn't common in code).