Libsigc++库的使用
概述
通常在图形用户界面程序中,我们希望检测事件的代码与处理事件的代码能够分开独立出来。我们可以使用回调函数的机制,注册函数指针来注册相关的处理函数,不过,在C++中,我们可以使用类型安全的库libsigc++。
Libsigc++库中提出了槽的概念,熟悉Qt的朋友应该对槽的概念不陌生,它其实是指向一个可作为回调的函数的引用,以下三种类型的函数都可作为槽:
1. 普通函数。
2. 重载了operator()的函数子对象(类)。
3. 如果对象所属的类继承了sigc::trackable, 它的成员函数也可以作为槽。
针对第三种类型的函数,libsigc++库提供了sigc::ptr_func()和sigc::mem_func()为分别从类的静态函数和对象的成员函数中创建槽。返回值类型是signal::slot,可通过emit()或operator()调用。另外,libsigc++也提出了信号的概念signals,它是模板类型sigc::signal实例, 可将信号与槽连接起来,当emit信号时,所有连接到信号的槽将会执行。
一个简单的示例
Signal发送方:
|
class AlienDetector { public: AlienDetector() { }
void run() { cout<<"AlienDetector is running"<<endl; // signal_detected.emit(); signal_detected(); } sigc::signal<void> signal_detected; }; |
槽函数定义,与信号的返回值类型一致:
|
void warn_people() { cout<<"There are aliens in the carpark!"<<endl; } |
连接信号和槽:
|
int main() { AlienDetector mydetector; mydetector.signal_detected.connect(sigc::ptr_fun(warn_people)); mydetector.run();
return 0; } |
头文件包含:
|
#include <iostream> #include <sigc++/sigc++.h> |
编译:
|
g++ example1.cc -o example1 `pkg-config --cflags --libs sigc++-2.0` |
使用成员函数作为槽
上述例子演示了普通函数作为槽函数,接下来的例子将显示如何将成员函数作为槽使用。
提供槽函数的类定义如下,必须从sigc::trackable继承:
|
class AlienAlerter : public sigc::trackable { public: AlienAlerter(char const* servername) { srvname = string(servername); }
void alert() { cout<<"server name: "<<srvname<<endl; } private: // ... string srvname; }; |
连接信号和槽
|
int main() { AlienDetector mydetector; AlienAlerter myalerter("localhost"); mydetector.signal_detected.connect(sigc::mem_fun(myalerter, &AlienAlerter::alert)); mydetector.run();
return 0; } |
带参数的信号
信号的类型sigc::signal的模板参数中第一个是返回值类型,后面都是信号参数的类型,如:
|
sigc::signal<void, std::string> |
那么对应的槽函数声明也必须为返回值为void, 接受一个参数为std::string的函数,即:
|
void warn_people(std::string where) { cout << "There are aliens in " << where << "!" << endl; } |
如前述AlienDetector类的声明修改如下:
|
class AlienDetector { public: AlienDetector();
void run();
sigc::signal<void, std::string> signal_detected; // changed }; |
连接信号和槽:
|
int main() { AlienDetector mydetector; mydetector.signal_detected.connect( sigc::ptr_fun(warn_people) );
mydetector.run();
return 0; } |
断开信号和槽之间的连接
信号sigc::signal的connect方法的返回值类型为:sigc::connection, 它提供了一个disconnect函数来断开信号和槽之间的连接。
高级话题
重新绑定(rebinding)
当信号与槽的类型不匹配时,连接时会出现编译错误。为了解决这种不匹配的情况,我们可以利用sigc::bind进行重绑定,便信号与槽之间的类型能够重新匹配。
假设我们定义了除返回值外, 不带任何参数的信号,这样与之连接的槽函数也不能接受任何参数。如果我们要利用一个已经写好的并需要传入参数的函数,我们可以通过sigc::bind作些处理,如下所示:
|
myaliendetector.signal_detected.connect(sigc::bind( sigc::ptr_fun(warn_people), "the carpark" ) ); |
其中sigc::bind(slot, arg), 如果槽函数接受多个参数,那么arg指的是最右边那个参数。
另外,返回值的类型也可以通过类似的方式重新绑定:
|
sigc::bind_return(slot, returnvalue) |
反过来,如果我们要利用一个已存在的函数作为槽函数,它接受一个参数,但是信号要求槽函数不接受任何参数,可以通过如下方式进行重新绑定:
|
myaliendetector.signal_detected.connect( sigc::hide<std::string>( sigc::ptr_fun(warn_people) ) ); |
,如果有多个参数,如上写法隐藏的是最右边的参数。
类型重定义(Retyping)
另一种情况是,当信号接受一个整型参数,但我们想让它与一个接受双精度类型的槽函数连接,这时需要进行类型重定义,可以通过sigc::retype模板类型,它与sigc::signal的模板参数一样。
|
void dostuff(double foo) { }
sigc::signal<void,int> asignal;
asignal.connect( sigc::retype<void, int>( slot(&dostuff) ) ); |
当只是返回类型不同时,则只需指定返回类型参数。
本文介绍了libsigc++库在C++中的应用,它提供了类型安全的信号与槽机制。文中详细讲解了如何创建槽,包括普通函数、函数对象和成员函数,并展示了如何连接信号和槽,以及如何断开连接。此外,还讨论了类型不匹配时的重绑定和类型重定义等高级话题。
2093

被折叠的 条评论
为什么被折叠?



