【发布时间】:2019-11-26 08:11:20
【问题描述】:
(我之前的一个问题有类似的措辞和例子,但问的是完全不同的东西。 在我寻求方法的想法之前。现在我在问如何获得特定的工作方法。)
我有一些订阅函数,当有事情发生时会调用我的回调。 (假设它是一个计时器,当经过一定的毫秒数时会传递给我一个对象。)查看 lambdas,std:function 和std:bind 我认为指针到方法的解决方案性能更高,更简单写(特别是对于订阅者),但我不太清楚最后一点。
这个例子有点像我的项目:我们有一个框架,由 Foo 表示,它只编写一次,我们将有许多由 Bar 表示的子类,这些子类将由具有更多领域知识但较少 C++ 知识的人编写.因此,我们希望对SubscribeTimer() 的调用尽可能简单。最后,应用程序是高性能的,我们希望消除堆使用,包括创建隐式 std::bind 对象等。
#include <iostream>
#include <functional>
using namespace std;
class Data { int i; };
class Foo {
public:
typedef void (Foo::*Timer_T)( Data* pd );
virtual void SubscribeTimer( int iMilliseconds, Timer_T pmethod );
virtual void SubscribeTimer( int iMilliseconds, std::function<void(Data*)> pfn ); // undesired
virtual void OnTimerA( Data* pd ) { cout << "Foo::OnTimerA called" << endl; };
};
void Foo::SubscribeTimer( int iMilliseconds, Timer_T pmethod ) {
Data d;
(this->*pmethod)( &d );
}
void Foo::SubscribeTimer( int iMilliseconds, std::function<void(Data*)> pfn ) { // undesired
Data d;
pfn( &d );
}
class Bar: public Foo {
public:
void Init();
virtual void OnTimerA( Data* pd ) { cout << "Bar::OnTimerA called" << endl; };
virtual void OnTimerB( Data* pd ) { cout << "Bar::OnTimerB called" << endl; };
};
void Bar::Init() {
// Works like I want it to: easy to subscribe, and high performance.
SubscribeTimer( 1000, &Foo::OnTimerA );
// What I'd like to do, but doesn't work.
//SubscribeTimer( 1000, &Bar::OnTimerB );
// Does exactly what I want except more complicated to write and I believe slower to run.
SubscribeTimer( 1000, std::bind( &Bar::OnTimerB, this, std::placeholders::_1 ) );
}
int main( int nArg, const char* apszArg[] ) {
Bar bar;
bar.Init();
}
正如预期的那样(如果您忽略了在Init() 对SubscribeTimer() 的调用中写入Foo:: 而不是Bar:: 的要求)程序输出:
Bar::OnTimerA called (from the version of SubscribeTimer() I like)
Bar::OnTimerB called (from the version of SubscribeTimer() I think is too verbose/slow)
所以这个例子完美地工作并且满足我的需要...... 除了子类只能为超类认为定义的方法名称注册处理程序,无论它们是否被定义。但实际上,子类可能希望为不同的事件注册许多处理程序,其名称是超类不知道的。
所以一句话:如何将OnTimerB() 传递到SubscribeTimer() 的方法指针版本中?我很高兴更改 Timer_T 定义、SubscribeTimer() 或其他任何内容。尽管如此,对于子类来说,成员指针解决方案没有比std::function 实现更复杂的意义,而且比std::function 实现更慢的解决方案也没有意义。另一方面,超类中增加的复杂性不是问题,因为它是一次性代码。
【问题讨论】:
标签: c++ c++11 c++14 c++17 stdbind