-
信号与槽通常被用于对象间的通信、事件驱动等场景,相比于回调函数的优势是动态连接、支持多对多、参数类型检查更安全、更加松耦合等。
-
这里提供一个C++实现的简易仿信号与槽的框架。注:QT中信号与槽是基于较复杂的元对象系统,而这里只是以基本功能为导向提供简易实现。
信号和槽函数的创建、连接、触发、断连。 -
code
#include <iostream>
#include <functional>
#include <vector>
#include <map>
#define CONNECT(signal, slot) signal.connect(slot, #slot)
#define DISCONNECT(signal, slot) signal.disconnect(#slot)
template <typename... Args>
class GenericSignal
{
public:
using SlotType = std::function<void(Args...)>;
void connect(SlotType slot, const std::string &slotName)
{
slots[slotName] = std::move(slot);
}
void disconnect(const std::string &slotName)
{
auto it = slots.find(slotName);
if (it != slots.end())
{
slots.erase(it);
}
}
template <typename... SignalArgs>
void emitSignal(SignalArgs &&...args) const
{
for (const auto &slotPair : slots)
{
slotPair.second(std::forward<SignalArgs>(args)...);
}
}
private:
std::map<std::string, SlotType> slots;
};
void slotFunction1(int arg1, const std::string &arg2)
{
std::cout << "Slot 1 called with " << arg1 << " and " << arg2 << std::endl;
}
void slotFunction2(int arg1, const std::string &arg2)
{
std::cout << "Slot 2 called with " << arg1 << " and " << arg2 << std::endl;
}
int main()
{
GenericSignal<int, const std::string &> signal;
CONNECT(signal, &slotFunction1);
CONNECT(signal, &slotFunction2);
std::cout << "Emitting signal..." << std::endl;
signal.emitSignal(1, "Hello");
DISCONNECT(signal, &slotFunction1);
std::cout << "\nEmitting signal after disconnecting slotFunction1..." << std::endl;
signal.emitSignal(2, "Hello");
return 0;
}
- result
Emitting signal...
Slot 1 called with 1 and Hello
Slot 2 called with 1 and Hello
Emitting signal after disconnecting slotFunction1...
Slot 2 called with 2 and Hello