信号槽技术由来已久, 早就听说在QT中大量应用,一起未曾研究, 最近要用到 libjingle, 看了相关文章和代码。
它利用了模板技术将 消息producer--触发信号的那个对象 和 consumer -- 接受信号的那个对象(槽) 进行解耦, 很好的简化了代码.
类似的技术常用的是 callback, 如典型的event and dispatch loop, onEvent, onConnect 等回调方式。
当设定的信号产生时, producer 对象调用 consumer对象的回调方法, 在实现上显然不如信号槽灵活
不说废话,让代码说话
一般的写法
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include "sigslot.h"
using namespace std;
using namespace sigslot;
//example 0
class CSwitch
{
public:
virtual void Clicked() = 0;
};
class CLight
{
public:
CLight():state(false) {}
void ToggleState() {
state = !state;
}
void TurnOn() { state=true; };
void TurnOff() { state=false; };
void printState() {
if(state) printf("on\n");
else printf("off\n");
}
private:
bool state;
};
class ToggleSwitch : public CSwitch
{
public:
ToggleSwitch(CLight& lp):m_lp(lp)
{}
virtual void Clicked()
{
m_lp.ToggleState();
}
private:
CLight& m_lp;
};
#ifdef __TEST_SIGSLOT__
int main(int argc, char* argv[])
#else
int sigslot_usage(int argc, char* argv[])
#endif
{
//example 1
CLight lp1, lp2;
CSwitch* pSw1 = new ToggleSwitch(lp1);
CSwitch* pSw2 = new ToggleSwitch(lp2);
lp1.printState();
pSw1->Clicked();
lp1.printState();
lp2.printState();
pSw2->Clicked();
lp2.printState();
delete pSw1;
delete pSw2;
return 0;
}
--- output---
off
on
off
on
用信号槽的写法如下,这其中用到的sigslot.h 来自 http://sigslot.sourceforge.net/ , 很好用的信号槽库,就一个头文件
例一
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include "sigslot.h"
using namespace std;
using namespace sigslot;
//example 1
class Switch
{
public:
void execute() {Clicked();}
signal0<> Clicked;
};
class Light : public has_slots<>
{
public:
Light():state(false) {}
void ToggleState() {
state = !state;
}
void TurnOn() { state=true; };
void TurnOff() { state=false; };
void printState() {
if(state) printf("on\n");
else printf("off\n");
}
private:
bool state;
};
#ifdef __TEST_SIGSLOT1__
int main(int argc, char* argv[])
#else
int sigslot_usage1(int argc, char* argv[])
#endif
{
//example 1
Switch sw1, sw2;
Light lp1, lp2;
sw1.Clicked.connect(&lp1, &Light::ToggleState);
sw2.Clicked.connect(&lp2, &Light::ToggleState);
lp1.printState();
sw1.execute();
lp1.printState();
lp2.printState();
sw2.execute();
lp2.printState();
return 0;
}
--- Output ---
off
on
off
on
例二
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <iostream>
#include "sigslot.h"
using namespace std;
using namespace sigslot;
//example 2
class Sender {
public:
sigslot::signal2<string, std::time_t> SignalDanger;
void Panic(){
SignalDanger("Help!", std::time(0));
}
};
class Receiver : public sigslot::has_slots<> {
public:
Receiver(Sender& sender) {
sender.SignalDanger.connect(this, &Receiver::OnDanger);
}
void OnDanger(string message, std::time_t time) {
if(message == "Help!") cout<<"help when "<<time<<endl;
}
};
#ifdef __TEST_SIGSLOT2__
int main(int argc, char* argv[])
#else
int sigslot_usage2(int argc, char* argv[])
#endif
{
Sender sender;
Receiver receiver(sender);
sender.Panic();
return 0;
}
--- Output ---
help when 1350872883
以上代码根据其官方文档整理, 接下来要看下信号槽的内部实现机制