c++ 11 实现简单 signal slot

本文介绍了一种在C++11中实现信号槽机制的方法,避免了使用libsig++与Qt信号槽机制的名称冲突问题。通过利用C++11的新特性,如std::function和模板,设计了一个简单的信号类,支持线程安全和异步信号发送。文章提供了详细的代码实现和示例,展示了如何连接和断开信号与槽。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

c++ 11以前要实现 signal slot 非常麻烦,需要重写很多代码。之前使用 libsig++ 后来发现 这代码中与qt 的slots emit等名称冲突。虽然可以解决,但是比较麻烦。所以 就使用 新的 c++特性,自行实现了简单的 signal 类。 目前实现比较简单。没有太多考虑异常或者智能情况。

     这里面包含了结合线程使用,编程异步信号的 部分代码.需要屏蔽掉才能正常使用.


#include <functional>
#include <map>
#include <vector>
#include "ScTypes.h"
#include "ScCoreDefine.h"

#define AsyncSignal
#ifdef AsyncSignal
#include "ScAsyncMessage.h"
#include "ScThread.h"
#include "ScMutex.h"
#include "ScReadWriteLock.h"
#endif

#ifdef PostMessage
#define PostMessageOld PostMessage
#undef  PostMessage
#endif
// A signal object may call multiple slots with the
// same signature. You can connect functions to the signal
// which will be called when the emit() method on the
// signal object is invoked. Any argument passed to emit()
// will be passed to the given functions.
//异步消息大约每秒d 70 万 r 500w
//不可使用引用作参数
namespace SimpleCpp {
	class CThread;

    class SCCORE_API CSignalInitializer {
    public:
        CSignalInitializer();
        ~CSignalInitializer();

        static CThread*	m_pThreadDefault;
        static CSignalInitializer m_signalInitializer;
    };

	template <class T_Ret, typename... Args>
	class CSignalConnection {
	public:
		CSignalConnection() {

		}
		CSignalConnection(const CSignalConnection& other) {
			m_pFun = other.m_pFun;
			m_pObject = other.m_pObject;
			m_function = other.m_function;
		}
		~CSignalConnection()
		{

		}

		CSignalConnection& operator =(const CSignalConnection& other) {
			m_pFun = other.m_pFun;
			m_pObject = other.m_pObject;
			m_function = other.m_function;

			return *this;
		}
	public:

		std::function<T_Ret(Args...)> m_function;
		void* m_pFun;
		void* m_pObject;
	};


	template <class T_Ret, typename... Args>
	class CSignal {

	public:

		CSignal(void* pOwner=nullptr, bool bThreadSafe=true)
#ifdef AsyncSignal
			: m_pThread(nullptr)

#endif
			//, m_pMutex(nullptr)
			, m_pOwner(pOwner)
		{
			//默认都要打开线程安全
			if (bThreadSafe)
			{
				//m_pMutex = new CMutex();
				m_pRWLock = new CReadWriteLock();
			}
		}

		// copy creates new signal
		CSignal(CSignal const& other)
#ifdef AsyncSignal
			: m_pThread(nullptr) 
#endif
			//, m_pMutex(nullptr)
		{
// 			if (other.m_pMutex)
// 			{
// 				m_pMutex = new CMutex();
// 			}
			
		}
		~CSignal() {
// 			for (auto it : m_lstSlots) {
// 				delete it.first;
// 			}
			if (m_pThread)
			{
				//m_pThread->RemoveMessage(this);
				m_pThread->RemoveSignal(this);
			}
			for (int i=0; i<m_lstSlots.size(); i++)
			{
				delete m_lstSlots[i];
			}
			m_lstSlots.clear();
// 			if (m_pMutex)
// 			{
// 				delete m_pMutex;
// 				m_pMutex = nullptr;
// 			}
			if (m_pRWLock)
			{
				delete m_pRWLock;
				m_pRWLock = nullptr;
			}
		}

		// connects a member function of a given object to this Signal  
// 		template < typename T_Fun, typename T_O, typename... A>
// 		int Connect(T_Fun&& fun, T_O&& object, A&& ... a) 
		template < typename T_Fun,  typename... A>
		int Connect(T_Fun&& fun,  A&& ... a)
		{
			ScDebug("%s: ptr fun \n", __FUNCTION__);
			CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
			pConnection->m_pFun = (void*)*(long long*)&fun;
			pConnection->m_pObject = (void*)nullptr;

			pConnection->m_function = std::bind(fun, a...);
			//pConnection->m_function = std::bind(fun, object, a...);
			//m_lstSlots.insert({ ++m_Id, std::bind(fun, object, a...) });
			//m_lstSlots.insert({ pFunction, pFunction->m_function });
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Lock();
// 				m_lstSlots.push_back(pConnection);
// 				m_pMutex->Unlock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->LockForWrite();
				m_lstSlots.push_back(pConnection);
				m_pRWLock->UnlockForWrite();
			}
			else
			{
				m_lstSlots.push_back(pConnection);
			}

			return 0;
		}
// 		template < typename T_Fun>
// 		int Connect(T_Fun&& fun)
// 		{
// 			ScDebug("%s: ptr fun \n", __FUNCTION__);
// 			CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
// 			pConnection->m_pFun = (void*)*(long long*)&fun;
// 			pConnection->m_pObject = (void*)nullptr;
// 
// 			pConnection->m_function = std::bind(fun);
// 			//pConnection->m_function = std::bind(fun, object, a...);
// 			if (m_pRWLock)
// 			{
// 				m_pRWLock->LockForWrite();
// 				m_lstSlots.push_back(pConnection);
// 				m_pRWLock->UnlockForWrite();
// 			}
// 			else
// 			{
// 				m_lstSlots.push_back(pConnection);
// 			}
// 
// 			return 0;
// 		}

		template <typename T_Ret1, typename T_O, typename... A>
		int Connect(T_Ret1 T_O::* fun, T_O* object, A&& ... a) {
			ScDebug("%s: mem fun \n", __FUNCTION__);
			CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
			pConnection->m_pFun = (void*)*(long long*)&fun;//(void*)*(long long*)&fun;
			pConnection->m_pObject = (void*)object;
			pConnection->m_function = std::bind(fun, object, a...);

			if (m_pRWLock)
			{
				m_pRWLock->LockForWrite();
				m_lstSlots.push_back(pConnection);
				m_pRWLock->UnlockForWrite();
			}
			else
			{
				m_lstSlots.push_back(pConnection);
			}
			return 0;
		}
		template < typename T_Fun,  typename... A>
		int Connect1(T_Fun* fun, A&& ... a) {
			ScDebug("%s: ptr fun \n", __FUNCTION__);
			CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
			pConnection->m_pFun = (void*)*(long long*)fun;
			pConnection->m_pObject = (void*)nullptr;

			pConnection->m_function = std::bind(fun, a...);
	 
			if (m_pRWLock)
			{
				m_pRWLock->LockForWrite();
				m_lstSlots.push_back(pConnection);
				m_pRWLock->UnlockForWrite();
			}
			else
			{
				m_lstSlots.push_back(pConnection);
			}

			return 0;
		}
		template <typename T_Ret1, typename T_O, typename... A>
		int Connect1(T_Ret1 T_O::* fun, T_O* object, A&& ... a) {
 			ScDebug("%s: mem fun \n", __FUNCTION__);
 			CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
			pConnection->m_pFun = (void*)*(long long*)&fun;//(void*)*(long long*)&fun;
 			pConnection->m_pObject = (void*)object;
 			pConnection->m_function = std::bind(fun, object, a...);
 
 			if (m_pRWLock)
 			{
 				m_pRWLock->LockForWrite();
 				m_lstSlots.push_back(pConnection);
 				m_pRWLock->UnlockForWrite();
 			}
 			else
 			{
 				m_lstSlots.push_back(pConnection);
 			}
			return 0;
		}

		template <typename T_Fun, typename T_O, typename... A>
		CSignalConnection<T_Ret, Args...> MemFun(T_Fun&& fun, T_O&& object, A&& ... a)
		{
			CSignalConnection<T_Ret, Args...> connection;
			connection.m_pFun = (void*)*(long long*)&fun;
			connection.m_pObject = (void*)&object;
			connection.m_function = std::bind(fun, object, a...);

			return connection;
		}
		template <typename T_Fun, typename T_O, typename... A>
		CSignalConnection<T_Ret, Args...> Fun(T_Fun&& fun, T_O&& object, A&& ... a)
		{
			CSignalConnection<T_Ret, Args...> connection;
			connection.m_pFun = (void*)*(long long*)&fun;
			connection.m_pObject = (void*)&object;
			connection.m_function = std::bind(fun, object, a...);

			return connection;
		}

		template <typename T_Fun, typename... A>
		CSignalConnection<T_Ret, Args...> PtrFun(T_Fun&& fun, A&& ... a)
		{
			CSignalConnection<T_Ret, Args...> connection;
			connection.m_pFun = (void*)*(long long*)&fun;
			connection.m_pObject = nullptr;
			//function.function = std::bind(fun, a...);
			return connection;
		}
		// connects a free function to the signal. The returned
        // can not use std::bind, use function ptr directly
		int Connect(std::function<T_Ret(Args...)> const& fun) {
             typedef T_Ret T_Fun(Args...);
             T_Fun* pFun = nullptr;
			 long long* pTmp = (long long*)fun.template target<T_Ret(*)(Args...)>();
            // fun.template target<decltype(pFun)>();
             //int64* pTmp = (int64*)fun.target<decltype(pFun)>();
			if (pTmp == nullptr)
			{//不能使用bind 方式绑定.
				return -1;
			}
			// 			;
			CSignalConnection<T_Ret, Args...> *pConnection = new CSignalConnection<T_Ret, Args...>();
			//pFunction->pFun = (void*)*(int64*)function.target<T_Ret(Args...)>();
			pConnection->m_pFun = (void*)*pTmp;
			pConnection->m_pObject = nullptr;
			pConnection->m_function = fun;

			//m_lstSlots.insert({ pFunction, fun });
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Lock();
// 				m_lstSlots.push_back(pConnection);
// 				m_pMutex->Unlock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->LockForWrite();
				m_lstSlots.push_back(pConnection);
				m_pRWLock->UnlockForWrite();
			}
			else
			{
				m_lstSlots.push_back(pConnection);
			}
			return 0;
		}
		//成员函数 mem function, 不可使用bind
		template < typename T_Fun, typename T_O, typename... A>
		int Disconnect(T_Fun&& fun, T_O&& object, A&& ... a) {
			CSignalConnection<T_Ret, Args...> connection;
			connection.m_pFun = (void*)*(long long*)&fun;
			connection.m_pObject = (void*)object;
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Lock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->LockForWrite();
			}
            typename std::vector<CSignalConnection<T_Ret, Args...> *> ::iterator item;
			for (item = m_lstSlots.begin(); item != m_lstSlots.end(); item++) {
				CSignalConnection<T_Ret, Args...>* pConnectionTmp;
				pConnectionTmp = *item;
				if (pConnectionTmp->m_pFun == connection.m_pFun
					&& pConnectionTmp->m_pObject == connection.m_pObject)
				{
					item = m_lstSlots.erase(item);
					delete pConnectionTmp;
					break;
				}
			}
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Unlock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->UnlockForWrite();
			}
			return 0;
		}
		//断开普通函数 free function , 不可使用 bind 
		int Disconnect(std::function<T_Ret(Args...)> const& fun) {

			long long* pTmp = (long long*)fun.template target<T_Ret(*)(Args...)>();
			if (pTmp == nullptr)
			{//不能使用bind 方式绑定.
				return -1;
			}

			CSignalConnection<T_Ret, Args...> connection;
			connection.m_pFun = (void*)*pTmp;
			connection.m_pObject = nullptr;
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Lock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->LockForWrite();
			}
            typename std::vector<CSignalConnection<T_Ret, Args...> *> ::iterator item;
			for (item = m_lstSlots.begin(); item != m_lstSlots.end(); item++) {
				CSignalConnection<T_Ret, Args...>* pConnectionTmp;
				pConnectionTmp = *item;
				if (pConnectionTmp->m_pFun == connection.m_pFun
					&& pConnectionTmp->m_pObject == connection.m_pObject)
				{
					item = m_lstSlots.erase(item);
					delete pConnectionTmp;
					break;
				}
			}
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Unlock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->UnlockForWrite();
			}
			return 0;
		}

		int Connect(CSignalConnection<T_Ret, Args...> connection)
		{
			CSignalConnection<T_Ret, Args...>* pNewConnection = new CSignalConnection<T_Ret, Args...>(connection);

			//m_lstSlots.insert({ pFunction, function.m_function });
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Lock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->LockForWrite();
			}

			m_lstSlots.push_back(pNewConnection);
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Unlock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->UnlockForWrite();
			}

			return 0;
		}

		// disconnects a previously connected function


		// disconnects all previously connected functions
		void Clear()  {
// 			for (auto it : m_lstSlots) {
// 				delete *it;
// 			}
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Lock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->LockForWrite();
			}
			for (int i = 0; i < m_lstSlots.size(); i++)
			{
				delete m_lstSlots[i];
			}
			m_lstSlots.clear();
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Unlock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->UnlockForWrite();
			}
		}

		// calls all connected functions
		T_Ret Emit(Args... p) {
			bool bVoid = std::is_same<T_Ret, void>::value;
			T_Ret ret(0);
#ifdef AsyncSignal
			if (m_pThread)
			{//异步信号
				//为了锁住 m_pThread 不被detach
				m_pRWLock->LockForWrite();
				if (!m_pThread)
				{
					m_pRWLock->UnlockForWrite();
					return ret;
				}
				CAsyncMessage<T_Ret, Args...>* pMessage = new CAsyncMessage<T_Ret, Args...>(p...);
				//pMessage->SetParams(p...);
				pMessage->m_pSignal = this;
				pMessage->m_pUserData = this;
				m_pThreadMessage = pMessage;
				m_pThread->PostMessage(pMessage);
				m_pRWLock->UnlockForWrite();
			}
			else 
#endif	
			{
// 				if (m_pMutex)
// 				{
// 					m_pMutex->Lock();
// 				}
				if (m_pRWLock)
				{
					m_pRWLock->LockForRead();
				}

				for (int i = 0; i < m_lstSlots.size(); i++)
				{
					m_lstSlots[i]->m_function(p...);
				}
// 				if (m_pMutex)
// 				{
// 					m_pMutex->Unlock();
// 				}
				if (m_pRWLock)
				{
					m_pRWLock->UnlockForRead();
				}
			}
			return ret;
		}
		//发射异步信号
		T_Ret EmitAsync(CThread* pThread, Args... p) {
			T_Ret ret(0);
#ifdef AsyncSignal
			if (pThread)
			{//异步信号
				CAsyncMessage<T_Ret, Args...>* pMessage = new CAsyncMessage<T_Ret, Args...>(p...);
				//pMessage->SetParams(p...);
				pMessage->m_pSignal = this;
				m_pThreadMessage = pMessage;
				pThread->PostMessage(pMessage);
			}
			else
#endif
			{
// 				if (m_pMutex)
// 				{
// 					m_pMutex->Lock();
// 				}
				if (m_pRWLock)
				{
					m_pRWLock->LockForRead();
				}
				for (int i = 0; i < m_lstSlots.size(); i++)
				{
					m_lstSlots[i]->m_function(p...);
				}
// 				if (m_pMutex)
// 				{
// 					m_pMutex->Unlock();
// 				}
				if (m_pRWLock)
				{
					m_pRWLock->UnlockForRead();
				}
			}
			return ret;
		}
		// assignment creates new Signal
		CSignal& operator=(CSignal const& other) {
			Clear();
			return *this;
		}
		
		vector<CSignalConnection<T_Ret, Args...>*>&	GetSlots()
		{
			return m_lstSlots;
		} 
		//附加到 thread, 那么消息将发到该线程去处理
		//也将是异步信号
		int		AttachThread(CThread* pThread) {
			if (pThread == nullptr)
			{
				m_pThread = CSignalInitializer::m_pThreadDefault;
			}
			else {
				m_pThread = pThread;
			}
			// 			if (!m_pMutex)
			// 			{//异步的一定需要是线程安全的。
			// 				m_pMutex = new CMutex();
// 			}
			if (!m_pRWLock)
			{//异步的一定需要是线程安全的。
				m_pRWLock = new CReadWriteLock();
			}
			return 0;
		};
		int		DetachThread(/*CThread* pThread*/)
		{
			m_pThread = nullptr;
			return 0;
		}
		int GetCount() {
			int nCount(0);
// 			if (m_pMutex)
// 			{
// 				m_pMutex->Lock();
// 				nCount = m_lstSlots.size();
// 				m_pMutex->Unlock();
// 			}
			if (m_pRWLock)
			{
				m_pRWLock->LockForRead();
				nCount = m_lstSlots.size();
				m_pRWLock->UnlockForRead();
			}
			else {
				nCount = m_lstSlots.size();
			}
			return nCount;
		}
		//
		CThread*	GetThread() {
			return m_pThread;
		};
		bool		Lock() {
// 			if (!m_pMutex)
// 			{
// 				return false;
// 			}
// 			return m_pMutex->Lock();
			if (!m_pRWLock)
			{
				return false;
			}
			return m_pRWLock->LockForRead();

		};
		bool		Unlock()
		{
// 			if (!m_pMutex)
// 			{
// 				return false;
// 			}
// 			return m_pMutex->Unlock();
			if (!m_pRWLock)
			{
				return false;
			}
			m_pRWLock->UnlockForRead();

			return true;
		};
		void*		GetOwner()
		{
			return m_pOwner;
		}
		void		SetOwner(void* pOwner)
		{
			m_pOwner = pOwner;
		}
	protected:
		//std::map<int, std::function<T_Ret(Args...)>> m_lstSlots;;
		//std::map<CFunction<T_Ret, Args...>*, std::function<T_Ret(Args...)>> m_lstSlots;
		std::vector<CSignalConnection<T_Ret, Args...>*>	m_lstSlots;
		CThread*	m_pThread;
		//CMutex*		m_pMutex;
		CReadWriteLock*	m_pRWLock=nullptr;
		void*		m_pOwner;
		CThreadMessage*	m_pThreadMessage=nullptr;
	};

  

使用connect或者disconnect, 直接传入函数地址。不要使用bind 方式传入。 这是为了 保存函数 地址和对象地址。以便 disconnect

测试(进行了修改,自由函数或者成员函数不再需要bind函数区分):

int TestFun()
{
	return 0;
}
class CTestClass {
public:
	int TestFun()
	{
		return 0;
	}
};

void TestSignal1()
{
	CTestClass obj;
	CSignal<int> sig;
	//sig.MemFun(&CTestClass::TestFun, &obj);

	sig.Connect(&CTestClass::TestFun, &obj);
	sig.Connect(&TestFun);

	ScDebug("%s: %p, %p\n", __FUNCTION__, &CTestClass::TestFun, &TestFun);
	//Function(&CTestClass::TestFun);

	//Function(&TestFun);
}

此类内部,有 thread。可以自行屏蔽。这是为了扩展为线程异步信号。

类似qt 信号一样。可以让信号在某个线程中异步回调Slot。

传统的 异步消息处理方式 都是 case xxxx: OnXXX这样为程序扩展带来很大麻烦。每一个消息需要做函数映射处理,同时消息处理函数必须是完全是相同参数。

直接将信号扩展为异步信号。可以在任何时候,灵活绑定行程异步消息处理过程。同时可以使用任意参数的函数做消息和对应处理函数。 这可以极大方便程序使用。 后面再继续贴出线程异步信号

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值