我正在编写一个程序,其中大部分是作为静态库编译的独立于平台的代码。然后我使用链接到静态库的任何特定平台apis编写程序。从实际程序中调用库中的函数显然很容易,但我不确定从库中与程序通信的最佳方法(最有效/最干净的实现)。
我已经研究过信号/插槽方法但是我担心性能(理想情况下一些绘制调用会经历这个)。否则,我能想到的唯一其他方法是使用仿函数实现的某种形式的回调,这应该更快,但这是最好的设计吗?
编辑:我的主要目标/要求是性能和易于实施。该库是用C ++编写的,并且已经使用了boost,因此增强信号是可能的,但它们的性能是否可以接受?
答案 0 :(得分:4)
以下是您从大致灵活到最不灵活的选择:
列出了几个信号和插槽实现here(特别是Boost.Signal)。这些对于实现Observer设计模式很有用,其中多个对象有兴趣接收通知。
您可以注册boost::function
回调。 boost::function
是任何可调用实体的包装:自由函数,静态函数,成员函数或函数对象。要包装成员函数,请使用boost::bind
,如example所示。用法示例:
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
typedef boost::function<void (void)> MouseCallback;
class Mouse
{
public:
void registerCallback(MouseCallback callback) {callback_ = callback;}
void notifyClicked() {if (callback_) callback_();}
private:
MouseCallback callback_;
};
class Foo
{
public:
void mouseClicked() {std::cout << "Mouse clicked!";}
};
int main()
{
Mouse mouse;
Foo foo;
mouse.registerCallback(boost::bind(&Foo::mouseClicked, &foo));
mouse.notifyClicked();
}
有一个名为FastDelegate的委托实现,其速度比boost::function
快。它使用了C ++标准不支持的“丑陋黑客”,但实际上所有编译器都支持它。
标准也支持The Impossibly Fast C++ Delegates,但并非所有编译器都支持。
正如c-smile建议的那样,您可以注册一个指向从回调接口(抽象类)派生的对象的指针。这是传统的Java回调方式。例如:
class MouseInputListener
{
public:
virtual void mouseClicked() = 0;
virtual void mouseReleased() = 0;
};
class Mouse
{
public:
Mouse() : listener_(0) {}
void registerListener(MouseInputListener* listener) {listener_ = listener;}
void notifyClicked() {if (listener_) listener_->mouseClicked();}
void notifyReleased() {if (listener_) listener_->mouseReleased();}
private:
MouseInputListener* listener_;
};
class Foo : public MouseInputListener
{
public:
virtual void mouseClicked() {cout << "Mouse clicked!";}
virtual void mouseReleased() {cout << "Mouse released!";}
};
您注册了一个指向回调自由函数的指针,以及一个额外的“上下文”无效指针。在回调函数中,将void*
强制转换为将处理事件的对象类型,并调用正确的方法。例如:
typedef void (*MouseCallback)(void* context); // Callback function pointer type
class Mouse
{
public:
Mouse() : callback_(0), context_(0) {}
void registerCallback(MouseCallback callback, void* context = 0)
{callback_ = callback; context_ = context;}
void notifyClicked() {if (callback_) callback_(context_);}
private:
MouseCallback callback_;
void* context_;
};
class Foo
{
public:
void mouseClicked() {cout << "Mouse clicked!";}
static void callback(void* context)
{static_cast<Foo*>(context)->mouseClicked();}
};
int main()
{
Mouse mouse;
Foo foo;
mouse.registerCallback(&Foo::callback, &foo);
mouse.notifyClicked();
}
我找到了一些性能基准:
他们应该让你知道什么是适当的回调机制。
正如您可以从数字中看到的那样,在性能成为问题之前,您必须每秒调用10,000到100,000次Boost信号。
如果不以极高的速率(每秒10-100万次)调用回调,则使用boost::signal
以获得最大的灵活性和自动连接生命周期管理。
如果以极高的速率调用回调,则从boost::function
开始,以获得最大的灵活性和可移植性。它仍然太慢,然后使用FastDelegate或C风格的回调。
答案 1 :(得分:1)
接口(抽象类)。库公开接口。并接受从库代码调用的回调接口。时间证明经典。为什么要发明其他东西?