signals的使用其实就是实现了观察者模式。
两个关键词:signal 和 slots ——信号和插槽。
信号其实就是Subject,插槽就是Observer
给信号连接上插槽,然后信号一触发,插槽上的函数就一触即发。
一个简单的使用signal和slots的例子:
1.先定义一个函数对象HelloWorld
(函数对象就是实现了operator()操作符的类)
struct HelloWorld
{
void operator()() const
{
std::cout << "Hello, World!" << std::endl;
}
};
2.定义信号signal类型的变量 sig
boost::signal<返回值 + 输入参数>
boost::signal<void ()> sig;
3.使用connect方法
connect的作用是将一个函数对象实例hello,连接到sig。如下:
HelloWorld hello;
sig.connect(hello);也可以用
sig.connect(HelloWorld()); // 调用HelloWord的默认构造函数 构造了一个HelloWord对象实例
上述的hello即为连接到signal的一个slot。
- slot除了可以是函数对象,也可以是函数指针:
void print_sum(float x, float y)
{
std::cout << "The sum is " << x+y << std::endl;
}
boost::signal<void (float, float)> sig;
sig.connect(&print_sum);
sig(5, 3);
- 一个signal可以连接多个slot:
多个slot也可以是相同的。顺序一般先进先调用,但是也有可能有副作用。
void print_sum(float x, float y)
{
std::cout << "The sum is " << x+y << std::endl;
}
boost::signal<void (float, float)> sig;
sig.connect(&print_sum);
sig.connect(&print_sum);
sig(5, 3);
如果对调用顺序有严格的要求,可以调用下面这个重载函数进行connect,增加要给参数groupname,int类型的,值越小,越早调用。
connect(groupname,slot)
4.调用sig
即调用连接到自己的slots——即hello。
sig();
5.断开连接
一般slot不会永久得连接到signal,一般slot用来连接过一些事件以后就会进行断开连接。例如:
void foo(); void bar(); signal<void()> sig; sig.connect(&foo); sig.connect(&bar); // disconnects foo, but not bar sig.disconnect(&foo);
注意:函数对象的断开,需要函数对象的类型具有可访问的==运算符,即可以使用disconnect方法的形式断开与给定函数对象等效的槽。
参考
https://www.boost.org/doc/libs/1_61_0/doc/html/signals/tutorial.html