I have one base class which holds a map
for function pointers like this
typedef void (BaseClass::*event_t)();
class BaseClass {
protected:
std::map<std::string, event_t> events;
public:
// Example event
void onFoo() {
// can be added easily to the map
}
};
Handling this works prefect, but now i want to make BaseClass
an abstract base class to derive from like this:
class SpecificClass : public BaseClass {
public:
void onBar() {
// this is gonna be difficult!
}
};
Although i can access the map from SpecificClass
i am not able to add onBar
because the event_t
type is only defined for the BaseClass
! Is there any possibility (maybe with templates?) which does not lead to define the event_t
for each class i will use...
(It is not neccessary to use templates! Any good/suitable approach would be nice.)
More background information:
This whole thing is for a text based RPG. My base class could be called Location
and the specifc one any location e.g. CivicCenter
. Each Location
object subscribes to my EventSystem
which notifies all neccessary objects when i fire an event. Therefore i want to store in a map some pointers to private functions holding the actions with their "name" like onSetOnFire
(xD) as the key.
This can't be done with your current
map
as it stands. Think about what would happen if you could put a child method into the map. Then you could pull a pointer-to-child-member (masquerading as base) out of the map, call it on a base class instance pointer, and then how would it call a derived class on a base class instance which obviously couldn't work.Would a polymorphic approach work?
After some thought and a redesign i was able to achieve what i wanted. Although i am stubborn and still using inheritance i have reimplemented the map. This is how it works now:
And now i can handle it like this:
With easy use of
std::bind
i am able to implement generic function pointers. When using parameters like instd::function<void(int, int)>
remeber to use either boost's_1
and_2
or lambda expressions like me:But this is just pointed out due to completeness of my solution.
Yes; stop using member pointers.
The more correct way of doing what you want is to have an event type and an object pointer. So an event fires on a specific object. The event type would be a non-member function (or a static member). It would be passed the object pointer. And it would call some actual member function of that object.
Nowadays, the event type could be a
std/boost::function
. However, since the function parameters have to stay the same type for all events, this doesn't really fix your problem. You can't callSpecificClass::onBar
from aBaseClass
pointer unless you do a cast to aSpecificClass
. And the event calling function would not know to do this. So you still can't putSpecificClass::onBar
in thestd/boost::function
object; you still need some standalone function to do the cast for you.This all just seems to be a terrible use of polymorphism. Why does
SpecificClass
need to derive fromBaseClass
at all? Can't they just be two unrelated classes?You have to use
static_cast
:This is because it is slightly dangerous to cast to
event_t
, you could accidently apply it to aBaseClass
instance.How it works (for the skeptical):
Here is what you should avoid, and why this is potentially dangerous:
The requirement for a
static_cast
makes it so you can't "accidentally" passDerivedClass
method pointers in. And if you think this is dangerous, just remember that it's a pointer, and pointers are always dangerous. Of course, there are ways you can do this that involve creating helper classes, but that requires a lot of extra code (possibly making a class for every function you want to pass as a callback). Or you could use closures in C++11, or something from Boost, but I realize that a lot of us do not have that option.