C++类和子类中的成员函数指针
我有一个基类,它包含一个像这样的函数指针的 map
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
}
};
处理这个工作完美,但现在我想使 BaseClass
成为一个抽象基类,如下所示:
class SpecificClass : public BaseClass {
public:
void onBar() {
// this is gonna be difficult!
}
};
虽然我可以从 SpecificClass
访问地图,但我无法添加 onBar
因为 event_t
类型仅为 BaseClass< 定义/代码>!是否有任何可能性(也许使用模板?)不会导致为我将使用的每个类定义
event_t
...
(没有必要使用模板!任何好的/合适的方法都是很好。)
更多背景信息:
这一切都是基于文本的角色扮演游戏。我的基类可以称为 Location
,具体的位置可以称为 CivicCenter
。每个 Location
对象都会订阅我的 EventSystem
,当我触发事件时,它会通知所有必要的对象。因此,我想在映射中存储一些指向私有函数的指针,这些函数以其“名称”(例如 onSetOnFire
(xD))作为键来保存操作。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这无法用您当前的
地图
来完成。想想如果您可以将子方法放入映射中,会发生什么。然后,您可以从映射中提取一个指向子成员的指针(伪装成基),在基类实例指针上调用它,然后它如何在基类实例上调用派生类,这显然不能工作。多态方法有效吗?
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?
是的;停止使用成员指针。
做你想做的事情的更正确的方法是拥有一个事件类型和一个对象指针。因此,事件会在特定对象上触发。事件类型将是非成员函数(或静态成员)。它将传递对象指针。它会调用该对象的一些实际成员函数。
如今,事件类型可以是 std/boost::function 。但是,由于所有事件的函数参数必须保持相同的类型,因此这并不能真正解决您的问题。除非转换为
SpecificClass
,否则无法从BaseClass
指针调用SpecificClass::onBar
。并且事件调用函数不知道要执行此操作。所以你仍然不能将SpecificClass::onBar
放入std/boost::function
对象中;您仍然需要一些独立的功能来为您进行转换。这一切似乎都是多态性的糟糕使用。为什么
SpecificClass
需要从BaseClass
派生?他们不能只是两个不相关的类吗?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?您必须使用
static_cast
:这是因为转换为
event_t
有点危险,您可能会意外地将其应用到BaseClass
实例。它是如何工作的(对于持怀疑态度的人):
这是您应该避免的内容,以及为什么这有潜在危险:
static_cast
的要求使得这样您就不会“意外”传递DerivedClass
方法指针。如果您认为这很危险,请记住它是一个指针,而指针总是危险的。当然,您可以通过多种方法来执行此操作,其中涉及创建帮助程序类,但这需要大量额外的代码(可能为您想要作为回调传递的每个函数创建一个类)。或者你可以使用 C++11 中的闭包,或者 Boost 中的某些东西,但我意识到我们很多人都没有这种选择。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.经过一番思考和重新设计,我能够实现我想要的。尽管我很顽固并且仍在使用继承,但我已经重新实现了地图。这就是它现在的工作方式:
现在我可以这样处理它:
通过轻松使用 std::bind 我能够实现通用函数指针。当使用
std::function
等参数时,请记住使用 boost 的_1
和_2
或 lambda 表达式像我一样:但这只是由于我的解决方案的完整性而指出的。
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.