[英]C++ member function pointers in class and subclass
我有一个基类,它包含像这样的函数指针的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
...
(使用模板不是必需的!任何好的/合适的方法都会很好。)
更多背景资料:
这一切都是基于文本的RPG。 我的基类可以称为Location
和特定的任何位置,例如CivicCenter
。 每个Location
对象都订阅我的EventSystem
,它在我触发事件时通知所有必要的对象。 因此,我想在一个地图中存储一些指向私有函数的指针,这些函数用onSetOnFire
(xD)作为键来保存带有“name”的动作。
目前的map
无法完成。 想想如果你可以将一个子方法放入地图会发生什么。 然后你可以从地图中拉出一个指向子的成员(伪装成基础),在基类实例指针上调用它,然后如何在基类实例上调用派生类,这显然不能工作。
多态方法会起作用吗?
是; 停止使用成员指针。
做你想做的更正确的方法是拥有一个事件类型和一个对象指针。 因此,事件会触发特定对象。 事件类型将是非成员函数(或静态成员)。 它将传递给对象指针。 它会调用该对象的一些实际成员函数。
如今,事件类型可以是std/boost::function
。 但是,由于函数参数必须保持所有事件的相同类型,这并不能解决您的问题。 你不能叫SpecificClass::onBar
从BaseClass
,除非你做一个转换为指针SpecificClass
。 事件调用函数不会知道这样做。 所以你仍然不能在std/boost::function
对象中放置SpecificClass::onBar
; 你仍然需要一些独立的功能来为你做演员表。
这一切似乎都是多态性的可怕用法。 为什么SpecificClass
需要从BaseClass
派生? 他们不能只是两个不相关的课程吗?
经过一番思考和重新设计,我能够实现我想要的。 虽然我很顽固,仍然使用继承,但我重新实现了地图。 这是它现在的工作方式:
class Location {
// ...
protected:
std::map<std::string, std::function<void(void)>> m_mEvents;
};
现在我可以像这样处理它:
class CivicCenter : public Location {
public:
CivicCenter() {
// this is done by a macro which lookes better than this
this->m_mEvents["onTriggerSomething"] =
std::bind(&CivicCenter::onTriggerSomething, this);
}
void onTriggerSomething() {
// ...
}
// ...
};
通过简单使用std::bind
我可以实现泛型函数指针。 当使用std::function<void(int, int)>
remeber中的参数来使用boost的_1
和_2
或像我这样的lambda表达式:
std::function<void(int,int)> f = [=](int a, int b) {
this->anotherFunctionWithParams(a, b);
};
但由于我的解决方案的完整性,我们只是指出了这一点。
你必须使用static_cast
:
event_t evt = static_cast<event_t>(&SpecificClass::onBar);
这是因为转换为event_t
有点危险,您可能会意外地将其应用于BaseClass
实例。
它是如何工作的(对于持怀疑态度的):
class BaseClass {
public:
typedef void (BaseClass::*callback_t)(); // callback method
void doSomething(callback_t callback) {
// some code
this->*callback();
// more code
}
void baseCallback(); // an example callback
};
class DerivedClass : public BaseClass {
public:
void derivedCallback();
void doWhatever() {
// some code
doSomething(&BaseClass::baseCallback);
// more code
doSomething(static_cast<callback_t>(&DerivedClass::derivedCallback));
// et cetera
};
这是你应该避免的,以及为什么这有潜在危险:
void badCodeThatYouShouldNeverWrite()
{
BaseClass x;
// DO NOT DO THIS IT IS BAD
x.doSomething(static_cast<callback_t>(&DerivedClass::derivedCallback));
}
对static_cast
的要求使得你不能“意外地”传递DerivedClass
方法指针。如果你认为这很危险,只要记住它是一个指针,指针总是危险的。 当然,有一些方法可以做到这一点,包括创建辅助类,但这需要大量额外的代码(可能为你想要作为回调传递的每个函数创建一个类)。 或者您可以在C ++ 11中使用闭包,或者使用Boost中的闭包,但我意识到我们很多人都没有这个选项。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.