委托是一个类,其内部维护一个装有函数包装器的容器。函数包装器把函数指针封装成类,这样使得需要委托的函数能够像普通对象一样作为参数传递。究其根本委托的核心为函数指针,而函数指针为C语言的多态思想,所以在面向对象语言中委托也可以作为一种多态手段。
#pragma once
#include <cstdint>
#include <unordered_map>
#include <functional>
template<typename T>
class Delegate
{
public:
void connect(std::function<T> func)
{
uint32_t index = convertPtrToUInt(&func);
if (_delegateMap.find(index) == _delegateMap.end())
{
_delegateMap.insert(std::make_pair(index, func));
}
}
void disconnect(std::function<T> func)
{
uint32_t index = convertPtrToUInt(&func);
if (_delegateMap.find(index) != _delegateMap.end())
{
_delegateMap.erase(index);
}
}
void operator += (std::function<T> func)
{
connect(func);
}
void operator -= (std::function<T> func)
{
disconnect(func);
}
template<typename ... Args>
void operator ()(Args&& ... args)
{
for (auto var : _delegateMap)
{
var.second(std::forward<Args>(args) ...);
}
}
private:
inline uint32_t convertPtrToUInt(void* fptr)
{
uint32_t value = 0;
memcpy_s(&value, sizeof(uint32_t), fptr, sizeof(void*));
return value;
}
std::unordered_map<uint32_t, std::function<T> > _delegateMap;
};
//测试代码
class Test1
{
public:
void function1()
{
std::cout << "call Test1::function1" << std::endl;
}
void function2(int param1)
{
std::cout << "call Test1::function2 and param1 is " << param1 << std::endl;
}
};
void function1(int param1)
{
std::cout << "call function and param1 is " << param1 << std::endl;
}
typedef void(__stdcall *Fun)(int a);
void __stdcall dllFunc(int param1)
{
std::cout << "call testDllFunc and param1 is " << param1 << std::endl;
}
void delegateTest()
{
Test1 testObj1;
Delegate<void()> delegateHandler0;
delegateHandler0.connect(std::bind(&Test1::function1, testObj1));
delegateHandler0();
Delegate<void(int)> delegateHandler1;
delegateHandler1.connect(function1);
delegateHandler1.connect(std::bind(&Test1::function2, testObj1, std::placeholders::_1));
delegateHandler1(1);
Fun func=dllFunc;
Delegate<void(int)>
delegateHandler;
delegateHandler += std::bind(func, std::placeholders::_1);
delegateHandler(33);
}