Qt信号槽机制可以很好地实现全局广播,具有类型安全,耦合松散,使用灵活等优点。Qt信号槽的本质就是函数指针,现在用函数指针来模拟一下信号槽的实现。
首先定义信号槽函数类。
class slotBase {
public:
virtual void doit() = 0;
};
//槽函数
template<class Receive>
class slot:public slotBase {
Receive *pRec;
void (Receive::*pFunc)();
public:
slot(Receive* pRec, void (Receive::*pFunc)()):pRec(pRec), pFunc(pFunc) {
}
void doit()
{
(pRec->*pFunc)();
}
};
槽函数中包含了接受指针和槽函数指针。这里的为了方便理解,将信号和槽都假定为void类型的无参函数指针。随后定义信号类:
//信号
class signal {
public:
template<class Receive>
void Bind(Receive*pRec, void(Receive::*pFunc)()) {
slotVecs.push_back(new slot<Receive>(pRec, pFunc));
}
void operator ()()
{
for (auto pFun : slotVecs) {
pFun->doit();
}
}
signal() {
}
//释放槽函数指针
~signal()
{
for (auto pFun : slotVecs) {
delete pFun;
pFun = nullptr;
}
}
private:
std::vector<slotBase*> slotVecs;
};
信号和槽的连接,相当于是一张表,一个信号可以对应多个槽函数。因此使用vector容器存放槽函数类。一个槽函数也可以被多个信号所连接,直接将信号和槽connect即可
#define connect(sender, signal, receiver, slot) ((sender)->signal.Bind(receiver, slot))
在发送信号时,将信号类中的vector函数指针容器遍历执行一遍即可。
//发送类
class Client {
public signals:
signal sig;
void sendMessage() {
emit sig();
}
};
//接收类
class Server {
public slots:
void print() {
std::cout << "received!!" << std::endl;
}
};
int main()
{
Client *client = new Client();
Server *server = new Server();
connect(client, sig, server, &Server::print);
client->sendMessage();
delete client;
client = nullptr;
delete server;
server = nullptr;
return 0;
}