C++ - 使用标准库实现事件和委托,信号和槽机制

 使用C++标准库简单实现事件触发机制   Event.h

/*
Author:StubbornHuang
Data:2023.1.31
Email:stubbornhuang@qq.com
*/


#ifndef _EVENT_H_
#define _EVENT_H_

#include <functional>
#include <map>
#include <type_traits>

#ifndef EVENT_NO_THREAD_SAFETY
#define EVENT_THREAD_SAFETY
#endif // !EVENT_NO_THREAD_SAFETY

#ifdef EVENT_THREAD_SAFETY
#include <atomic>
#include <mutex>
#endif // EVENT_THREAD_SAFETY

#ifdef EVENT_THREAD_SAFETY
#define DELEGATE_ID_TYPE std::atomic_uint64_t
#else
#define DELEGATE_ID_TYPE std::uint64_t
#endif // EVENT_THREAD_SAFETY

namespace stubbornhuang
{
	static DELEGATE_ID_TYPE DELEGATE_ID = 1;

	template<typename Prototype> class Event;

	template<typename ReturnType, typename ...Args>
	class Event <ReturnType(Args...)>
	{
	private:
		using return_type = ReturnType;
		using function_type = ReturnType(Args ...);
		using std_function_type = std::function<function_type>;
		using function_pointer = ReturnType(*)(Args...);

	private:
		class Delegate
		{
		public:
			Delegate() = delete;
			Delegate(int id,std_function_type std_function_func)
				:m_Handler(nullptr),m_Id(-1)
			{
				if (std_function_func == nullptr)
					return;

				m_Id = id;
				m_Handler = std_function_func;
			}

			void Invoke(Args ...args)
			{
				if (m_Handler != nullptr)
				{
					m_Handler(args...);
				}
			}

		private:
			int m_Id;
			std_function_type m_Handler;
		};

	public:
		int AddDelegate(std_function_type std_function_func)
		{
			if (std_function_func == nullptr)
				return -1;
			
			std::shared_ptr<Delegate> pDelegate = std::make_shared<Delegate>(DELEGATE_ID, std_function_func);

#ifdef EVENT_THREAD_SAFETY
			std::lock_guard<std::mutex> guard_mutex(m_event_mutex);
#endif // EVENT_THREAD_SAFETY


			m_delegates.insert(std::pair<int, std::shared_ptr<Delegate>>(DELEGATE_ID, pDelegate));

			return DELEGATE_ID++;
		}

		bool RemoveDelegate(int delegate_id)
		{
#ifdef EVENT_THREAD_SAFETY
			std::lock_guard<std::mutex> guard_mutex(m_event_mutex);
#endif // EVENT_THREAD_SAFETY

			if (m_delegates.count(delegate_id) == 0)
				return false;

			m_delegates.erase(delegate_id);

			return true;
		}


		int operator += (std_function_type std_function_func)
		{
			return AddDelegate(std_function_func);
		}

		bool operator -= (int delegate_id)
		{
			return RemoveDelegate(delegate_id);
		}

		void Invoke(Args ...args)
		{
#ifdef EVENT_THREAD_SAFETY
			std::lock_guard<std::mutex> guard_mutex(m_event_mutex);
#endif // EVENT_THREAD_SAFETY

			for (const auto& key : m_delegates)
			{
				key.second->Invoke(args...);
			}
		}

		bool Invoke(int delegate_id, Args ...args)
		{
#ifdef EVENT_THREAD_SAFETY
			std::lock_guard<std::mutex> guard_mutex(m_event_mutex);
#endif // EVENT_THREAD_SAFETY

			if (m_delegates.count(delegate_id) == 0)
				return false;

			m_delegates[delegate_id]->Invoke(args...);


			return true;
		}

		void operator() (Args ...args)
		{
#ifdef EVENT_THREAD_SAFETY
			std::lock_guard<std::mutex> guard_mutex(m_event_mutex);
#endif // EVENT_THREAD_SAFETY

			for (const auto& key : m_delegates)
			{
				key.second->Invoke(args...);
			}
		}

		bool operator() (int delegate_id, Args ...args)
		{
#ifdef EVENT_THREAD_SAFETY
			std::lock_guard<std::mutex> guard_mutex(m_event_mutex);
#endif // EVENT_THREAD_SAFETY

			if (m_delegates.count(delegate_id) == 0)
				return false;

			m_delegates[delegate_id]->Invoke(args...);


			return true;
		}

		int GetDelegateSize()
		{
#ifdef EVENT_THREAD_SAFETY
			std::lock_guard<std::mutex> guard_mutex(m_event_mutex);
#endif // EVENT_THREAD_SAFETY

			return m_delegates.size();
		}


	private:
		std::map<int, std::shared_ptr<Delegate>> m_delegates;

#ifdef EVENT_THREAD_SAFETY

		std::mutex m_event_mutex;
#endif // EVENT_THREAD_SAFETY
	};
}


#endif // !_EVENT_H_

在上述代码中我们使用template<typename ReturnType, typename ...Args>对事件类Event进行了模板化,使用变参模板typename ...Args自定义事件绑定的委托函数参数列表,可以接受多个不同类型的参数。使用std::vector存储绑定事件的std::function<ReturnType(Args...)>的委托函数,并重载+=操作符添加委托函数。

上述事件工具类Event的使用示例如下:

不带参数

#include <iostream>

#include "Event.h"

class Button
{
public:
	Button()
	{

	}

	virtual~Button()
	{

	}

public:
	stubbornhuang::Event<void()> OnClick;
};

void Click()
{
	std::cout << "Button Click" << std::endl;
}


class Example
{
public:
	void Click()
	{
		std::cout << "Example Click" << std::endl;
	}
};

int main()
{
	Button button;

	button.OnClick += Click; // 静态函数做委托函数

	Example example;
	button.OnClick += std::bind(&Example::Click, example); // 成员函数做委托函数 

	button.OnClick += []() { std::cout << "Lambda Click" << std::endl;  }; // 匿名函数做委托函数

	button.OnClick();

	return 0;
}

带参数:

#include <iostream>

#include "event.h"

void Sum(int a, int b)
{
	std::cout << "Sum = " << a + b << std::endl;
}

class Example
{
public:
	Example()
	{

	}
	virtual~ Example()
	{

	}

	void Print(int a, int b)
	{
		std::cout << "a = " << a <<" " << "b = " << b << std::endl;
	}
};


int main()
{
	stubbornhuang::Event<void(int, int)> event;

	std::cout << "-----Add Delegate-----" << std::endl;
	int sum_fuc_delegate_id = event.AddDelegate(Sum); // static function

	event += [](int a, int b) { std::cout << "Sub = " << a - b << std::endl; }; // lambda function

	Example example;
	event += std::bind(&Example::Print, example, std::placeholders::_1, std::placeholders::_2); // class member function

	event(1,5);


	std::cout<<std::endl << "-----Remove Delegate-----" << std::endl;
	event -= (sum_fuc_delegate_id);

	event(1, 5);

	return 0;
}

该类默认是线程安全的,如果不想要线程安全,可以在包含头文件之前定义EVENT_NO_THREAD_SAFETY即可,该类同时也是模板类,支持定义任何返回类型和可变参数的事件类,并通过返回委托函数ID,对委托函数进行删除操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值